diff --git a/local/recipes/qt/qtbase/source/.cmake.conf b/local/recipes/qt/qtbase/source/.cmake.conf index e1e19d2ed2..83c1a65e3b 100644 --- a/local/recipes/qt/qtbase/source/.cmake.conf +++ b/local/recipes/qt/qtbase/source/.cmake.conf @@ -4,10 +4,13 @@ # ensure that when this file is included the second time in a toplevel buld # (directly by qtbase) we actually add the extra definitions if (NOT DEFINED QT_SUPERBUILD OR DEFINED QT_REPO_MODULE_VERSION) - set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1") + set(QT_EXTRA_INTERNAL_TARGET_DEFINES + "QT_LEAN_HEADERS=1" + "QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD=1" + ) endif() -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.11.1") set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") set(QT_COPYRIGHT "Copyright (C) The Qt Company Ltd. and other contributors.") diff --git a/local/recipes/qt/qtbase/source/.release-timestamp b/local/recipes/qt/qtbase/source/.release-timestamp index 8d8aab74fc..9940a5a213 100644 --- a/local/recipes/qt/qtbase/source/.release-timestamp +++ b/local/recipes/qt/qtbase/source/.release-timestamp @@ -1 +1 @@ -QT_PACKAGEDATE_STR=2026-03-17 \ No newline at end of file +QT_PACKAGEDATE_STR=2026-05-08 \ No newline at end of file diff --git a/local/recipes/qt/qtbase/source/.tag b/local/recipes/qt/qtbase/source/.tag index f4a9c131c4..64e9a1db95 100644 --- a/local/recipes/qt/qtbase/source/.tag +++ b/local/recipes/qt/qtbase/source/.tag @@ -1 +1 @@ -8ba7ea4b77a4b8f1948760221e264917ddc9e1c8 +59c81a3c2247b821b9b84b4eb8d939b77e07e276 diff --git a/local/recipes/qt/qtbase/source/cmake/QtBaseGlobalTargets.cmake b/local/recipes/qt/qtbase/source/cmake/QtBaseGlobalTargets.cmake index 50a7f6596c..f6439e9f25 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtBaseGlobalTargets.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtBaseGlobalTargets.cmake @@ -459,6 +459,13 @@ elseif(WASM) "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" @ONLY) qt_install(PROGRAMS "${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/qt-wasmtestrunner.py" DESTINATION "${INSTALL_LIBEXECDIR}") +elseif(WIN32) + qt_copy_or_install(FILES "cmake/windows/app.exe.manifest.in" + DESTINATION "${__GlobalConfig_install_dir}/windows" + ) + file(COPY "cmake/windows/app.exe.manifest.in" + DESTINATION "${__GlobalConfig_install_dir}/windows" + ) endif() # Install CI support files to libexec. diff --git a/local/recipes/qt/qtbase/source/cmake/QtBuildHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtBuildHelpers.cmake index 14b8270562..7fc4cfe2e6 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtBuildHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtBuildHelpers.cmake @@ -298,11 +298,13 @@ function(qt_internal_get_qt_build_public_helpers out_var) QtPublicPluginHelpers QtPublicPluginHelpers_v2 QtPublicSbomAttributionHelpers + QtPublicSbomBuildToolHelpers QtPublicSbomCommonGenerationHelpers QtPublicSbomCpeHelpers QtPublicSbomCycloneDXHelpers QtPublicSbomDocumentNamespaceHelpers QtPublicSbomDepHelpers + QtPublicSbomExternalReferenceHelpers QtPublicSbomFileHelpers QtPublicSbomGenerationHelpers QtPublicSbomGenerationCycloneDXHelpers @@ -312,6 +314,7 @@ function(qt_internal_get_qt_build_public_helpers out_var) QtPublicSbomPurlHelpers QtPublicSbomPythonHelpers QtPublicSbomQtEntityHelpers + QtPublicSbomRelationshipHelpers QtPublicSbomSystemDepHelpers QtPublicTargetHelpers QtPublicTestHelpers diff --git a/local/recipes/qt/qtbase/source/cmake/QtBuildPathsHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtBuildPathsHelpers.cmake index fba3d01cc3..a249cb3358 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtBuildPathsHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtBuildPathsHelpers.cmake @@ -243,6 +243,14 @@ macro(qt_internal_set_qt_apple_support_files_path) endif() endmacro() +macro(qt_internal_set_qt_windows_support_files_path) + # This is analogous to what we have in QtConfig.cmake.in. It's copied here so that + # tests can be built in tree. + if(WIN32) + set(__qt_internal_cmake_windows_support_files_path "${QT_CMAKE_DIR}/windows") + endif() +endmacro() + macro(qt_internal_set_qt_staging_prefix) if(NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "") set(QT_STAGING_PREFIX "${CMAKE_STAGING_PREFIX}") @@ -267,6 +275,8 @@ macro(qt_internal_setup_paths_and_prefixes) qt_internal_set_qt_cmake_dir() qt_internal_set_qt_apple_support_files_path() + + qt_internal_set_qt_windows_support_files_path() endmacro() # Returns the prefix for the variables defined by HostInfo package. The prefix diff --git a/local/recipes/qt/qtbase/source/cmake/QtBuildRepoExamplesHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtBuildRepoExamplesHelpers.cmake index bf2247611e..e1527aa794 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtBuildRepoExamplesHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtBuildRepoExamplesHelpers.cmake @@ -370,10 +370,6 @@ function(qt_internal_add_example_external_project subdir) cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${singleOpts}" "${multiOpts}") - if(QT_FEATURE_developer_build) - set(QT_LINT_EXAMPLES ON) - endif() - _qt_internal_get_build_vars_for_external_projects( CMAKE_DIR_VAR qt_cmake_dir PREFIXES_VAR qt_prefixes @@ -388,10 +384,6 @@ function(qt_internal_add_example_external_project subdir) list(APPEND var_defs -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${qt_cmake_dir}/qt.toolchain.cmake ) - if(QT_LINT_EXAMPLES) - list(APPEND var_defs -DQT_LINT_EXAMPLES=ON) - endif() - else() list(PREPEND CMAKE_PREFIX_PATH ${qt_prefixes}) @@ -404,6 +396,16 @@ function(qt_internal_add_example_external_project subdir) endif() endif() + if(QT_FEATURE_developer_build) + set(QT_LINT_EXAMPLES ON) + endif() + + # This might be set even without a developer build, e.g. in CI options, so it's a separate + # check. + if(QT_LINT_EXAMPLES) + list(APPEND var_defs -DQT_LINT_EXAMPLES:BOOL=ON) + endif() + # We we need to augment the CMAKE_MODULE_PATH with the current repo cmake build dir, to find # files like FindWrapBundledFooConfigExtra.cmake. set(module_paths "${qt_prefixes}") diff --git a/local/recipes/qt/qtbase/source/cmake/QtCMakeVersionHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtCMakeVersionHelpers.cmake index 73b40b4a61..348986ec69 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtCMakeVersionHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtCMakeVersionHelpers.cmake @@ -376,12 +376,12 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL \"4.0\" set(CMAKE_POLICY_VERSION_MINIMUM \"\${__qt_toolchain_cmake_policy_version_minimum}\") message(DEBUG \"Setting CMAKE_POLICY_VERSION_MINIMUM to \" - \"\${__qt_toolchain_cmake_policy_version_minimum}\ in toolchain file.\") + \"\${__qt_toolchain_cmake_policy_version_minimum} in toolchain file.\") endif() ") else() message(FATAL_ERROR "Unknown TYPE value '${arg_TYPE}'. " - " Supported values are COMMAND_LINE and VAR_ASSIGNMENT.") + " Supported values are COMMAND_LINE and TOOLCHAIN_FILE_ASSIGNMENT.") endif() endif() diff --git a/local/recipes/qt/qtbase/source/cmake/QtConfig.cmake.in b/local/recipes/qt/qtbase/source/cmake/QtConfig.cmake.in index d24dbb0324..7003c20880 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtConfig.cmake.in +++ b/local/recipes/qt/qtbase/source/cmake/QtConfig.cmake.in @@ -79,6 +79,10 @@ if(APPLE) endif() endif() +if(WIN32) + set(__qt_internal_cmake_windows_support_files_path "${_qt_import_prefix}/windows") +endif() + # Public helpers available to all Qt packages. set(__qt_public_files_to_include @QT_PUBLIC_FILES_TO_INCLUDE@ diff --git a/local/recipes/qt/qtbase/source/cmake/QtFlagHandlingHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtFlagHandlingHelpers.cmake index b32acc4cfa..18c11e4ed1 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtFlagHandlingHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtFlagHandlingHelpers.cmake @@ -1462,8 +1462,8 @@ function(qt_internal_set_up_config_optimizations_like_in_qmake) # Todo: # When the new toolchain is fixed, and it doesn't fall back to the legacy # anymore by default, then we should be able to remove this workaround. - if(ANDROID AND ANDROID_COMPILER_FLAGS MATCHES "(^| )-g") - qt_internal_remove_compiler_flags("-g") + if(ANDROID AND ANDROID_COMPILER_FLAGS MATCHES "(^| )-g( |$)") + qt_internal_remove_compiler_flags("(^| )-g( |$)" REGEX) qt_internal_add_compiler_flags(FLAGS "-g" CONFIGS DEBUG RELWITHDEBINFO) endif() diff --git a/local/recipes/qt/qtbase/source/cmake/QtModuleHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtModuleHelpers.cmake index fd224b234f..027039d152 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtModuleHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtModuleHelpers.cmake @@ -682,7 +682,7 @@ function(qt_internal_add_module target) foreach(public_lib IN LISTS arg_PUBLIC_LIBRARIES) if("${public_lib}" MATCHES "^(Qt|${QT_CMAKE_EXPORT_NAMESPACE})::(.*)Private$") message(AUTHOR_WARNING - "${target} specfies ${public_lib} in its PUBLIC_LIBRARIES option. " + "${target} specifies ${public_lib} in its PUBLIC_LIBRARIES option. " "Public modules should not link publicly to Private modules, because that " "exposes private module headers to user projects without them opting into it. " "Update the project to use the LIBRARIES keyword instead." diff --git a/local/recipes/qt/qtbase/source/cmake/QtPluginHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPluginHelpers.cmake index 952f96e74b..9febf4d9f5 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPluginHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPluginHelpers.cmake @@ -344,10 +344,9 @@ function(qt_internal_add_plugin target) qt_internal_wrap_private_modules("${target}" OUT_VAR qt_libs_private LIBRARIES ${qt_libs_private}) - list(APPEND qt_register_target_depentdencies_args PRIVATE ${qt_libs_private}) + list(APPEND qt_register_target_dependencies_args PRIVATE ${qt_libs_private}) endif() - qt_internal_register_target_dependencies("${target}" - ${qt_register_target_dependencies_args}) + qt_internal_register_target_dependencies("${target}" ${qt_register_target_dependencies_args}) if(target_type STREQUAL STATIC_LIBRARY) if(qt_module_target) @@ -392,6 +391,28 @@ function(qt_internal_add_plugin target) set(test_plugin_arg TEST_PLUGIN) endif() + # Some plugins like the sqldriver ones can be built as part of the main repo or as a + # separate standalone project. We need to make sure we exclude loading the Qt prebuilt + # plugins when loading such a project regardless which way it is built. + if(QT_STANDALONE_PROJECT_NAME) + set(project_names_arg "${QT_STANDALONE_PROJECT_NAME}") + + if(QT_PARENT_PROJECT_NAME) + list(APPEND project_names_arg "${QT_PARENT_PROJECT_NAME}") + else() + message(WARNING + "QT_STANDALONE_PROJECT_NAME is set to '${QT_STANDALONE_PROJECT_NAME}', but " + "QT_PARENT_PROJECT_NAME is not set. This can cause issues when building the " + "standalone project. Set QT_PARENT_PROJECT_NAME to the submodule's " + "root CMakeLists.txt project name to avoid this warning." + ) + endif() + else() + set(project_names_arg "${PROJECT_NAME}") + endif() + list(PREPEND project_names_arg "PROJECT_NAMES") + string(REPLACE ";" " " project_names_arg "${project_names_arg}") + configure_package_config_file( "${QT_CMAKE_DIR}/QtPluginConfig.cmake.in" "${config_build_dir}/${INSTALL_CMAKE_NAMESPACE}${target}Config.cmake" @@ -406,7 +427,7 @@ function(qt_internal_add_plugin target) _qt_internal_should_include_targets( TARGETS ${target} NAMESPACE ${INSTALL_CMAKE_NAMESPACE}:: - PROJECT_NAME ${PROJECT_NAME} + ${project_names_arg} OUT_VAR_SHOULD_SKIP __qt_${target}_skip_include_targets_file ${test_plugin_arg} ) diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicAppleHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicAppleHelpers.cmake index 5d90c45401..1256b7f080 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicAppleHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicAppleHelpers.cmake @@ -685,6 +685,30 @@ function(_qt_internal_set_apple_localizations target) return() endif() + get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST) + if (NOT plist_file) + return() + endif() + + if(NOT "${QT_I18N_SOURCE_LANGUAGE}" STREQUAL "") + _qt_internal_plist_buddy("${plist_file}" + COMMANDS "print CFBundleDevelopmentRegion" + OUTPUT_VARIABLE existing_dev_region + ) + if(existing_dev_region) + _qt_internal_plist_buddy("${plist_file}" + COMMANDS + "Set CFBundleDevelopmentRegion ${QT_I18N_SOURCE_LANGUAGE}" + ) + else() + _qt_internal_plist_buddy("${plist_file}" + COMMANDS + "Add CFBundleDevelopmentRegion string" + "Set CFBundleDevelopmentRegion ${QT_I18N_SOURCE_LANGUAGE}" + ) + endif() + endif() + set(supported_languages "${QT_I18N_TRANSLATED_LANGUAGES}") if("${QT_I18N_TRANSLATED_LANGUAGES}" STREQUAL "") get_target_property(supported_languages "${target}" _qt_apple_supported_languages) @@ -692,10 +716,6 @@ function(_qt_internal_set_apple_localizations target) return() endif() endif() - get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST) - if (NOT plist_file) - return() - endif() _qt_internal_plist_buddy("${plist_file}" COMMANDS "print CFBundleLocalizations" @@ -712,20 +732,6 @@ function(_qt_internal_set_apple_localizations target) "Delete CFBundleAllowMixedLocalizations" ) endif() - - if(NOT "${QT_I18N_SOURCE_LANGUAGE}" STREQUAL "") - _qt_internal_plist_buddy("${plist_file}" - COMMANDS "print CFBundleDevelopmentRegion" - OUTPUT_VARIABLE existing_dev_region - ) - if(NOT existing_dev_region) - _qt_internal_plist_buddy("${plist_file}" - COMMANDS - "Add CFBundleDevelopmentRegion string" - "Set CFBundleDevelopmentRegion ${QT_I18N_SOURCE_LANGUAGE}" - ) - endif() - endif() endfunction() function(_qt_internal_set_ios_simulator_arch target) diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicCMakeHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicCMakeHelpers.cmake index fb41230bb2..e0834eb1c2 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicCMakeHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicCMakeHelpers.cmake @@ -104,6 +104,9 @@ function(__qt_internal_get_possible_cmake_dirs out_paths prefix_path) if(EXISTS "${prefix_path}/lib/cmake") list(APPEND ${out_paths} "${prefix_path}/lib/cmake") endif() + if(EXISTS "${prefix_path}/lib64/cmake") + list(APPEND ${out_paths} "${prefix_path}/lib64/cmake") + endif() list(REMOVE_DUPLICATES ${out_paths}) set(${out_paths} "${${out_paths}}" PARENT_SCOPE) @@ -1055,9 +1058,14 @@ endfunction() # `OUT_VAR_SHOULD_SKIP` # Output variable indicating if the `include(*Targets.cmake)` should be skipped # +# `PROJECT_NAMES` +# The original project names that defined the current Config.cmake file at the time of the +# generation. For now only used for plugins. Mostly it's just the main repo project name, +# but for some projects like the sqldriver one that can be built standalone, there can be +# more than one. +# # `PROJECT_NAME` -# The original project that defined the current Config.cmake file at the time of the -# generation. For now only used for plugins. +# Deprecated. Same as the one above, but only takes a single value. Kept for compatibility. # # `TEST_PLUGIN` # If the module is a TEST_PLUGIN, we do additional checks based on @@ -1073,10 +1081,11 @@ function(_qt_internal_should_include_targets) set(single_args NAMESPACE OUT_VAR_SHOULD_SKIP - PROJECT_NAME + PROJECT_NAME # deprecated ) set(multi_args TARGETS + PROJECT_NAMES ) cmake_parse_arguments(PARSE_ARGV 0 arg "${option_args}" "${single_args}" "${multi_args}") @@ -1124,7 +1133,15 @@ function(_qt_internal_should_include_targets) endif() endforeach() + set(project_names "") + if(arg_PROJECT_NAMES) + list(APPEND project_names ${arg_PROJECT_NAMES}) + endif() if(arg_PROJECT_NAME) + list(APPEND project_names ${arg_PROJECT_NAME}) + endif() + + if(project_names) # Check if we are in a top-level build and which submodules will be included if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS AND DEFINED Qt_SOURCE_DIR) # All projects will be rebuilt so skip any include targets @@ -1134,7 +1151,7 @@ function(_qt_internal_should_include_targets) # Check if we are building the current project if(NOT QT_INTERNAL_BUILD_STANDALONE_PARTS AND - PROJECT_NAME STREQUAL arg_PROJECT_NAME) + PROJECT_NAME IN_LIST project_names) # We are currently building the project, so skip the include targets set(${arg_OUT_VAR_SHOULD_SKIP} ON PARENT_SCOPE) return() @@ -1142,7 +1159,7 @@ function(_qt_internal_should_include_targets) # Check if we are building the standalone tests if(arg_TEST_PLUGIN AND QT_BUILD_STANDALONE_TESTS AND - PROJECT_NAME STREQUAL arg_PROJECT_NAME) + PROJECT_NAME IN_LIST project_names) set(${arg_OUT_VAR_SHOULD_SKIP} ON PARENT_SCOPE) return() endif() diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCommonGenerationHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCommonGenerationHelpers.cmake index 8e308ee4d3..0e276d3199 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCommonGenerationHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCommonGenerationHelpers.cmake @@ -1,6 +1,13 @@ # Copyright (C) 2025 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause +# Save the 'macros base dir' in a global property instead of a variable, to allow access in a +# deferred function where the variable might not be accessible by the function scope. +# We explicitly don't set CMAKE_CURRENT_FUNCTION_LIST_DIR as we do in some other cases, because +# that can be overridden by a different file depending on the inclusion order of the +# cmake files, and thus pointing to a different dir. +set_property(GLOBAL PROPERTY __qt_sbom_generation_helpers_base_dir "${CMAKE_CURRENT_LIST_DIR}") + # Helper function to get common project related variables for SBOM generation for both SPDX and # CycloneDX formats. function(_qt_internal_sbom_get_common_project_variables) @@ -70,7 +77,9 @@ function(_qt_internal_sbom_get_common_project_variables) # Prevent collision with other generated SPDXID with -[0-9]+ suffix. string(REGEX REPLACE "-([0-9]+)$" "\\1" arg_PROJECT_FOR_SPDX_ID "${arg_PROJECT_FOR_SPDX_ID}") - set(project_spdx_id "SPDXRef-${arg_PROJECT_FOR_SPDX_ID}") + _qt_internal_sbom_get_spdx_id_unique_suffix(spdx_id_unique_suffix) + set(project_spdx_id "SPDXRef-${arg_PROJECT_FOR_SPDX_ID}${spdx_id_unique_suffix}") + set(${arg_OUT_VAR_PROJECT_FOR_SPDX_ID} "${project_spdx_id}" PARENT_SCOPE) _qt_internal_sbom_set_default_option_value_and_error_if_empty(SUPPLIER "") @@ -105,7 +114,7 @@ function(_qt_internal_sbom_save_common_path_variables_in_global_properties) OUTPUT OUTPUT_RELATIVE_PATH SBOM_DIR - PROPERTY_SUFFIX + SBOM_FORMAT ) set(multi_args "") cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -137,7 +146,13 @@ function(_qt_internal_sbom_save_common_path_variables_in_global_properties) get_filename_component(install_sbom_dir "${install_sbom_path}" DIRECTORY) set(install_sbom_path_without_ext "${install_sbom_dir}/${output_file_name_without_ext}") - set(suffix "${arg_PROPERTY_SUFFIX}") + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + else() + message(FATAL_ERROR "Unknown SBOM_FORMAT: ${arg_SBOM_FORMAT}") + endif() set_property(GLOBAL PROPERTY _qt_sbom_build_output_path${suffix} "${build_sbom_path}") set_property(GLOBAL PROPERTY _qt_sbom_build_output_path_without_ext${suffix} @@ -204,6 +219,25 @@ function(_qt_internal_sbom_get_common_path_variables_from_global_properties) endif() endfunction() +# Create the build directory that will contain all the intermediate generated sbom files. +function(_qt_internal_sbom_create_sbom_staging_dir) + set(opt_args "") + set(single_args + OUT_VAR_SBOM_DIR + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(NOT arg_OUT_VAR_SBOM_DIR) + message(FATAL_ERROR "OUT_VAR_SBOM_DIR argument is required.") + endif() + + _qt_internal_get_current_project_sbom_dir(sbom_dir) + file(MAKE_DIRECTORY "${sbom_dir}") + set(${arg_OUT_VAR_SBOM_DIR} "${sbom_dir}" PARENT_SCOPE) +endfunction() + # Helper function to create a staging file for SBOM generation. # It is the file that will be incrementally assembled by having content appended to it. # Also creates the intro file that will add the assembled content for the SBOM project, aka for the @@ -211,19 +245,20 @@ endfunction() function(_qt_internal_sbom_create_sbom_staging_file) set(opt_args "") set(single_args - CONTENT SBOM_FORMAT REPO_PROJECT_NAME_LOWERCASE - OUT_VAR_CREATE_STAGING_FILE - OUT_VAR_SBOM_DIR + SBOM_DIR + ) + set(multi_args + RELATIONSHIP_STRINGS ) - set(multi_args "") cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) - # Create the directory that will contain all sbom related files. - _qt_internal_get_current_project_sbom_dir(sbom_dir) - file(MAKE_DIRECTORY "${sbom_dir}") + if(NOT arg_SBOM_DIR) + message(FATAL_ERROR "SBOM_DIR argument is required") + endif() + set(sbom_dir "${arg_SBOM_DIR}") if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") set(doc_base_name "SPDXRef-DOCUMENT") @@ -234,6 +269,14 @@ function(_qt_internal_sbom_create_sbom_staging_file) ") _qt_internal_get_staging_area_spdx_file_path(staging_area_file) set(starting_message "Starting SPDX SBOM generation in build dir: ${staging_area_file}") + set(extra_intro_content "") + set(project_relationship_strings "") + if(arg_RELATIONSHIP_STRINGS) + list(JOIN arg_RELATIONSHIP_STRINGS "\n" arg_RELATIONSHIP_STRINGS) + + # Prepend a newline to separate from the very first always there relationship. + string(APPEND extra_intro_content "\n${arg_RELATIONSHIP_STRINGS}") + endif() elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") set(doc_base_name "cydx-document") set(doc_extension "cdx.in.toml") @@ -242,12 +285,40 @@ function(_qt_internal_sbom_create_sbom_staging_file) _qt_internal_get_staging_area_cydx_file_path(staging_area_file) set(starting_message "Starting CycloneDX SBOM TOML file generation in build dir: ${staging_area_file}") + set(extra_intro_content "") + + if(arg_RELATIONSHIP_STRINGS) + list(JOIN arg_RELATIONSHIP_STRINGS "\n" arg_RELATIONSHIP_STRINGS) + set(project_relationship_strings "${arg_RELATIONSHIP_STRINGS}") + else() + set(project_relationship_strings "") + endif() endif() - # Generate project document intro spdx file. + # Assemble final intro content. + get_property(intro_content GLOBAL PROPERTY _qt_sbom_project_intro_content${suffix}) + if(NOT intro_content) + message(FATAL_ERROR "Missing intro content for SBOM generation.") + endif() + + if(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + string(REPLACE "" "${project_relationship_strings}" + intro_content "${intro_content}") + endif() + + if(extra_intro_content) + string(APPEND intro_content "${extra_intro_content}") + endif() + + # Final new line to separate the main package from rest of info. + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + string(APPEND intro_content "\n") + endif() + + # Generate project document intro file. set(document_intro_file_name "${sbom_dir}/${doc_base_name}-${arg_REPO_PROJECT_NAME_LOWERCASE}.${doc_extension}") - file(GENERATE OUTPUT "${document_intro_file_name}" CONTENT "${content}") + file(GENERATE OUTPUT "${document_intro_file_name}" CONTENT "${intro_content}") get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) if(is_multi_config) @@ -256,7 +327,7 @@ function(_qt_internal_sbom_create_sbom_staging_file) set(multi_config_suffix "") endif() - # Create cmake file to append the document intro spdx to the staging file. + # Create cmake file to append the document intro to the staging file. set(create_staging_file "${sbom_dir}/append_document_to_staging${suffix}${multi_config_suffix}.cmake") @@ -269,9 +340,7 @@ function(_qt_internal_sbom_create_sbom_staging_file) file(WRITE \"${staging_area_file}\" \"\${content}\") ") file(GENERATE OUTPUT "${create_staging_file}" CONTENT "${content}") - - set(${arg_OUT_VAR_CREATE_STAGING_FILE} "${create_staging_file}" PARENT_SCOPE) - set(${arg_OUT_VAR_SBOM_DIR} "${sbom_dir}" PARENT_SCOPE) + set_property(GLOBAL PROPERTY _qt_sbom_cmake_intro_file${suffix} "${create_staging_file}") endfunction() # Helper function to save common project info like supplier, project name, spdx id in global @@ -285,7 +354,9 @@ function(_qt_internal_sbom_save_project_info_in_global_properties) PROJECT PROJECT_SPDX_ID ) - set(multi_args "") + set(multi_args + EXTERNAL_REFERENCE_SBOM_DIRS + ) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) @@ -295,6 +366,34 @@ function(_qt_internal_sbom_save_project_info_in_global_properties) set_property(GLOBAL PROPERTY _qt_sbom_project_name "${arg_PROJECT}") set_property(GLOBAL PROPERTY _qt_sbom_project_spdx_id "${arg_PROJECT_SPDX_ID}") + + # Used for finding external reference spdx documents. + if(arg_EXTERNAL_REFERENCE_SBOM_DIRS) + set_property(GLOBAL APPEND PROPERTY _qt_internal_sbom_dirs + ${arg_EXTERNAL_REFERENCE_SBOM_DIRS}) + endif() +endfunction() + +# Helper function to save sbom intro content (per sbom format) in a global property. +function(_qt_internal_sbom_save_intro_content) + set(opt_args "") + set(single_args + SBOM_FORMAT + CONTENT + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(arg_SBOM_FORMAT STREQUAL "SPDX_V2") + set(suffix "") + elseif(arg_SBOM_FORMAT STREQUAL "CYDX_V1_6") + set(suffix "_cydx") + else() + message(FATAL_ERROR "Unknown SBOM_FORMAT: ${arg_SBOM_FORMAT}") + endif() + + set_property(GLOBAL PROPERTY _qt_sbom_project_intro_content${suffix} "${content}") endfunction() # Helper function to get cmake include files for SBOM generation from global properties. @@ -320,7 +419,10 @@ function(_qt_internal_sbom_get_cmake_include_files) _qt_internal_sbom_collect_cmake_include_files(includes JOIN_WITH_NEWLINES - PROPERTIES _qt_sbom_cmake_include_files${suffix} _qt_sbom_cmake_end_include_files${suffix} + PROPERTIES + _qt_sbom_cmake_intro_file${suffix} + _qt_sbom_cmake_include_files${suffix} + _qt_sbom_cmake_end_include_files${suffix} ) # Before checksum includes are included after the verification codes have been collected @@ -443,8 +545,13 @@ function(_qt_internal_sbom_create_build_time_sbom_targets) set(build_sbom_install_prefix "${CMAKE_BINARY_DIR}") endif() + get_property(macro_module_base_dir GLOBAL PROPERTY __qt_sbom_generation_helpers_base_dir) _qt_internal_get_current_project_sbom_dir(sbom_dir) set(content " + # Include helpers functions. + include(\"${macro_module_base_dir}/QtPublicCMakeHelpers.cmake\") + include(\"${macro_module_base_dir}/QtPublicSbomExternalReferenceHelpers.cmake\") + # QT_SBOM_BUILD_TIME be set to FALSE at install time, so don't override if it's set. # This allows reusing the same cmake file for both build and install. if(NOT DEFINED QT_SBOM_BUILD_TIME) diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCycloneDXHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCycloneDXHelpers.cmake index aa38f17227..69b9fdbc82 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCycloneDXHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomCycloneDXHelpers.cmake @@ -239,12 +239,20 @@ function(_qt_internal_sbom_get_cyclone_bom_serial_number) endif() endfunction() +# Returns the bom version field that is part of a bom-link to refer to the target in an +# external CycloneDX document. +function(_qt_internal_sbom_get_cydx_external_urn_bom_version target out_var) + # Currently 1, but we might change it to be configurable in the future. + set(bom_version "1") + set(${out_var} "${bom_version}" PARENT_SCOPE) +endfunction() + # See https://github.com/CycloneDX/guides/blob/main/SBOM/en/0x52-Linking.md function(_qt_internal_sbom_get_cydx_external_bom_link target out_var) get_target_property(spdx_id "${target}" _qt_sbom_spdx_id) get_target_property(bom_serial_number "${target}" _qt_sbom_cydx_bom_serial_number_uuid) - set(bom_version "1") + _qt_internal_sbom_get_cydx_external_urn_bom_version("${target}" bom_version) set(bom_link "urn:cdx:${bom_serial_number}/${bom_version}#${spdx_id}") set(${out_var} "${bom_link}" PARENT_SCOPE) diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDepHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDepHelpers.cmake index 794f3f77db..518cd26d69 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDepHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDepHelpers.cmake @@ -4,21 +4,20 @@ # Walks a target's direct dependencies and assembles a list of relationships between the packages # of the target dependencies. # Currently handles various Qt targets and system libraries. -# For SPDX documents, it collects the relationships in OUT_SPDX_RELATIONSHIPS. -# For CYDX documents, it collects the dependencies (not relationship info) in OUT_CYDX_DEPENDENCIES. +# Collects the relationships in OUT_SBOM_RELATIONSHIP_ENTRIES. # If a CYDX dependency is in an external docuemnt, the dependency is added to -# OUT_EXTERNAL_TARGET_DEPENDENCIES instead. +# OUT_EXTERNAL_TARGET_DEPENDENCIES as well. function(_qt_internal_sbom_handle_target_dependencies target) set(opt_args "") set(single_args SPDX_ID - OUT_CYDX_DEPENDENCIES - OUT_SPDX_RELATIONSHIPS + OUT_SBOM_RELATIONSHIP_ENTRIES OUT_EXTERNAL_TARGET_DEPENDENCIES ) set(multi_args LIBRARIES PUBLIC_LIBRARIES + SBOM_DEPENDENCIES ) cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) @@ -81,15 +80,16 @@ function(_qt_internal_sbom_handle_target_dependencies target) set(all_direct_libraries ${libraries} ${public_libraries} ${sbom_dependencies}) list(REMOVE_DUPLICATES all_direct_libraries) - set(regular_cydx_dependencies "") - set(regular_spdx_dependencies "") - - set(external_cydx_dependencies "") - set(external_spdx_dependencies "") + set(regular_relationship_entries "") + set(external_relationship_entries "") set(external_target_dependencies "") - # Go through each direct linked lib. - foreach(direct_lib IN LISTS all_direct_libraries) + set(libs_to_process ${all_direct_libraries}) + + # Go through all collected direct linked libs. More might be added during the processing + # due to handling of WrapFoo -> Qt::BundledFoo libraries. + while(libs_to_process) + list(POP_FRONT libs_to_process direct_lib) if(NOT TARGET "${direct_lib}") continue() endif() @@ -114,12 +114,13 @@ function(_qt_internal_sbom_handle_target_dependencies target) foreach(lib_walked_target IN LISTS lib_walked_targets) get_target_property(is_3rdparty_bundled_lib "${lib_walked_target}" _qt_module_is_3rdparty_library) - _qt_internal_sbom_get_spdx_id_for_target("${lib_walked_target}" lib_spdx_id) # Add a dependency on the vendored lib instead of the Wrap target. - if(is_3rdparty_bundled_lib AND lib_spdx_id) - list(APPEND regular_cydx_dependencies "${lib_spdx_id}") - list(APPEND regular_spdx_dependencies "${lib_spdx_id}") + if(is_3rdparty_bundled_lib) + message(DEBUG + "Replacing SBOM dependency on '${direct_lib}' with dependency on " + "bundled target '${lib_walked_target}' for target '${target}'") + list(APPEND libs_to_process "${lib_walked_target}") set(bundled_targets_found TRUE) endif() endforeach() @@ -159,37 +160,36 @@ function(_qt_internal_sbom_handle_target_dependencies target) if(NOT is_dependency_in_external_document) # If the target is not in the external document, it must be one built as part of the # current project. - list(APPEND regular_cydx_dependencies "${lib_spdx_id}") - list(APPEND regular_spdx_dependencies "${lib_spdx_id}") + set(relationship_entry + SBOM_RELATIONSHIP_ENTRY + SBOM_RELATIONSHIP_FROM + "${target}" + SBOM_RELATIONSHIP_TYPE + DEPENDS_ON + SBOM_RELATIONSHIP_TO + "${direct_lib}" + ) + list(APPEND regular_relationship_entries ${relationship_entry}) else() # Refer to the package in the external document. This can be the case # in a top-level build, where a system library is reused across repos, or for any # regular dependency that was built as part of a different project. - _qt_internal_sbom_add_external_target_dependency("${direct_lib}" - OUT_CYDX_DEPENDENCIES extra_cydx_dependencies - OUT_SPDX_DEPENDENCIES extra_spdx_dependencies + _qt_internal_sbom_add_external_target_dependency( + TARGET "${target}" + DEPENDENCY_TARGET "${direct_lib}" + OUT_SBOM_RELATIONSHIP_ENTRIES extra_relationship_entries OUT_TARGET_DEPENDENCIES extra_target_dependencies ) - if(extra_spdx_dependencies) - list(APPEND external_cydx_dependencies ${extra_cydx_dependencies}) - list(APPEND external_spdx_dependencies ${extra_spdx_dependencies}) + if(extra_relationship_entries) + list(APPEND external_relationship_entries ${extra_relationship_entries}) list(APPEND external_target_dependencies ${extra_target_dependencies}) endif() endif() - endforeach() + endwhile() - set(spdx_relationships "") + set(all_relationship_entries ${external_relationship_entries} ${regular_relationship_entries}) - # Keep the external dependencies first, so they are neatly ordered. - foreach(dep_spdx_id IN LISTS external_spdx_dependencies regular_spdx_dependencies) - set(relationship "${package_spdx_id} DEPENDS_ON ${dep_spdx_id}") - list(APPEND spdx_relationships "${relationship}") - endforeach() - - set(all_cydx_dependencies ${external_cydx_dependencies} ${regular_cydx_dependencies}) - - set(${arg_OUT_CYDX_DEPENDENCIES} "${all_cydx_dependencies}" PARENT_SCOPE) - set(${arg_OUT_SPDX_RELATIONSHIPS} "${spdx_relationships}" PARENT_SCOPE) + set(${arg_OUT_SBOM_RELATIONSHIP_ENTRIES} "${all_relationship_entries}" PARENT_SCOPE) set(${arg_OUT_EXTERNAL_TARGET_DEPENDENCIES} "${external_target_dependencies}" PARENT_SCOPE) endfunction() @@ -223,25 +223,39 @@ function(_qt_internal_sbom_is_external_target_dependency target) set(${arg_OUT_VAR} "${part_of_other_repo}" PARENT_SCOPE) endfunction() -# Handles generating an external document reference SDPX element for each target package that is -# located in a different spdx document, and collects the reference in OUT_SPDX_DEPENDENCIES. -# In case of CycloneDX, we just collect the dependency spdx id (bom-ref) and the target name, -# which are added to OUT_CYDX_DEPENDENCIES and OUT_TARGET_DEPENDENCIES respectively. -function(_qt_internal_sbom_add_external_target_dependency target) +# Handles generating an external document reference SDPX element for each ${arg_DEPENDENCY_TARGET} +# package that is located in a different spdx document, and collects the relationship in +# OUT_SBOM_RELATIONSHIP_ENTRIES. +# In case of CycloneDX, we also collect the dependency target name in OUT_TARGET_DEPENDENCIES. +function(_qt_internal_sbom_add_external_target_dependency) set(opt_args "") set(single_args - OUT_CYDX_DEPENDENCIES - OUT_SPDX_DEPENDENCIES + TARGET + DEPENDENCY_TARGET + OUT_SBOM_RELATIONSHIP_ENTRIES OUT_TARGET_DEPENDENCIES ) set(multi_args "") - cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) - _qt_internal_sbom_get_spdx_id_for_target("${target}" dep_spdx_id) + if(NOT arg_TARGET) + message(FATAL_ERROR "TARGET is required.") + endif() + if(NOT arg_DEPENDENCY_TARGET) + message(FATAL_ERROR "DEPENDENCY_TARGET is required.") + endif() + if(NOT arg_OUT_SBOM_RELATIONSHIP_ENTRIES) + message(FATAL_ERROR "OUT_SBOM_RELATIONSHIP_ENTRIES is required.") + endif() + if(NOT arg_OUT_TARGET_DEPENDENCIES) + message(FATAL_ERROR "OUT_TARGET_DEPENDENCIES is required.") + endif() + + _qt_internal_sbom_get_spdx_id_for_target("${arg_DEPENDENCY_TARGET}" dep_spdx_id) if(NOT dep_spdx_id) - message(DEBUG "Could not add external target dependency on ${target} " + message(DEBUG "Could not add external target dependency on ${arg_DEPENDENCY_TARGET} " "because no spdx id could be found") set(${arg_OUT_CYDX_DEPENDENCIES} "" PARENT_SCOPE) set(${arg_OUT_SPDX_DEPENDENCIES} "" PARENT_SCOPE) @@ -249,29 +263,45 @@ function(_qt_internal_sbom_add_external_target_dependency target) return() endif() - set(cydx_dependencies "") - set(spdx_dependencies "") + set(relationship_entries "") set(target_depdendencies "") - # Get the external document path and the repo it belongs to for the given target. - get_property(relative_installed_repo_document_path TARGET ${target} + # Get the external document path and the repo it belongs to for the given target, + # as well as the spdx document namespace, and cydx serial number. + get_property(relative_installed_repo_document_path TARGET "${arg_DEPENDENCY_TARGET}" PROPERTY _qt_sbom_spdx_relative_installed_repo_document_path) - get_property(project_name_lowercase TARGET ${target} + get_property(project_name_lowercase TARGET "${arg_DEPENDENCY_TARGET}" PROPERTY _qt_sbom_spdx_repo_project_name_lowercase) + get_property(spdx_document_namespace TARGET "${arg_DEPENDENCY_TARGET}" + PROPERTY _qt_sbom_spdx_repo_document_namespace) + + get_property(bom_serial_number_uuid TARGET "${arg_DEPENDENCY_TARGET}" + PROPERTY _qt_sbom_cydx_bom_serial_number_uuid) + if(relative_installed_repo_document_path AND project_name_lowercase) - _qt_internal_sbom_get_external_document_ref_spdx_id( - "${project_name_lowercase}" external_document_ref) + _qt_internal_sbom_get_external_document_ref_spdx_id_from_sbom_target( + TARGET "${arg_DEPENDENCY_TARGET}" + OUT_VAR external_document_ref + CREATE_TEMPORARY_REF_WHEN_MISSING + ) get_cmake_property(known_external_document _qt_known_external_documents_${external_document_ref}) - set(spdx_dependency "${external_document_ref}:${dep_spdx_id}") + set(relationship_entry + SBOM_RELATIONSHIP_ENTRY + SBOM_RELATIONSHIP_FROM + "${arg_TARGET}" + SBOM_RELATIONSHIP_TYPE + DEPENDS_ON + SBOM_RELATIONSHIP_TO + "${arg_DEPENDENCY_TARGET}" + ) - list(APPEND cydx_dependencies "${dep_spdx_id}") - list(APPEND spdx_dependencies "${spdx_dependency}") - list(APPEND target_depdendencies "${target}") + list(APPEND relationship_entries "${relationship_entry}") + list(APPEND target_depdendencies "${arg_DEPENDENCY_TARGET}") # Only add a reference to the external document package, if we haven't done so already. if(NOT known_external_document) @@ -282,23 +312,38 @@ function(_qt_internal_sbom_add_external_target_dependency target) set(external_document "${relative_installed_repo_document_path}") - _qt_internal_sbom_generate_add_external_reference( - EXTERNAL_DOCUMENT_FILE_PATH "${external_document}" - EXTERNAL_DOCUMENT_INSTALL_PREFIXES ${install_prefixes} - EXTERNAL_DOCUMENT_SPDX_ID "${external_document_ref}" - ) + # We need to make the external document target name unique to the currently active + # project, otherwise we risk trying to override the document details of an existing + # external document target when processing multiple SBOM projects within a single + # cmake invocation. + _qt_internal_sbom_get_root_project_name_lower_case(current_project_name) + set(external_document_target + "ExternalDocumentProject-${project_name_lowercase}-for-${current_project_name}") - set_property(GLOBAL PROPERTY - _qt_known_external_documents_${external_document_ref} TRUE) - set_property(GLOBAL APPEND PROPERTY - _qt_known_external_documents "${external_document_ref}") + if(QT_SBOM_GENERATE_SPDX_V2) + _qt_internal_sbom_add_external_reference_document("${external_document_target}" + NO_SCAN_FILE_AT_CONFIGURE_TIME + SBOM_FORMAT SPDX_V2_TAG_VALUE + SPDX_V2_DOCUMENT_REF_ID "${external_document_ref}" + SPDX_V2_DOCUMENT_NAMESPACE "${spdx_document_namespace}" + EXTERNAL_DOCUMENT_FILE_PATH "${external_document}" + EXTERNAL_DOCUMENT_SEARCH_PATHS ${install_prefixes} + ) + endif() + + if(QT_SBOM_GENERATE_CYDX_V1_6) + _qt_internal_sbom_add_external_reference_document("${external_document_target}" + NO_SCAN_FILE_AT_CONFIGURE_TIME + SBOM_FORMAT CYDX_V1_JSON + CYDX_URN_SERIAL_NUMBER "${bom_serial_number_uuid}" + ) + endif() endif() else() message(AUTHOR_WARNING - "Missing spdx document path for external target dependency: ${target}") + "Missing spdx document path for external target dependency: ${arg_DEPENDENCY_TARGET}") endif() - set(${arg_OUT_CYDX_DEPENDENCIES} "${cydx_dependencies}" PARENT_SCOPE) - set(${arg_OUT_SPDX_DEPENDENCIES} "${spdx_dependencies}" PARENT_SCOPE) + set(${arg_OUT_SBOM_RELATIONSHIP_ENTRIES} "${relationship_entries}" PARENT_SCOPE) set(${arg_OUT_TARGET_DEPENDENCIES} "${target_depdendencies}" PARENT_SCOPE) endfunction() diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDocumentNamespaceHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDocumentNamespaceHelpers.cmake index 0293c163de..dc22999a7c 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDocumentNamespaceHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomDocumentNamespaceHelpers.cmake @@ -304,6 +304,74 @@ function(_qt_internal_sbom_compute_qt_uniqueish_document_namespace_infix) endif() endfunction() +# Computes a short unique-ish sha suffix to embed into all Qt package SPDX ids, to ensure that each +# package spdx id is distinct enough between Qt builds. +# +# The use case is referencing multiple versions of the the same target, within a project that +# mixes multiple Qt versions, like Qt for MCU. +# +# E.g. record that MyLib depends on Qt Core 6.8.3 from qtbase spdx doc1, and that MyLib2 depends +# on Qt Core 6.9.1 from qtbase spdx doc2, within the generated project doc that contains MyLib and +# MyLib2. +# +# Default hash length chosen to be 12, to have a probability of 0.001 collisions when there are +# 750000 releases of the same Qt repo, according to +# https://en.wikipedia.org/wiki/Birthday_problem#Probability_table +function(_qt_internal_sbom_compute_uniqueish_spdx_id_suffix) + set(opt_args "") + set(single_args + SPDX_NAMESPACE + OUT_VAR_UNIQUE_SUFFIX + HASH_LENGTH + ) + set(multi_args "") + + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(QT_SBOM_NO_AUTO_SPDX_SUFFIX) + set(${arg_OUT_VAR_UNIQUE_SUFFIX} "" PARENT_SCOPE) + return() + endif() + + if(NOT arg_OUT_VAR_UNIQUE_SUFFIX) + message(FATAL_ERROR "OUT_VAR_UNIQUE_SUFFIX must be set") + endif() + + if(NOT arg_SPDX_NAMESPACE) + message(FATAL_ERROR "SPDX_NAMESPACE must be set") + endif() + + if(QT_SBOM_FAKE_DETERMINISTIC_BUILD + # This is to allow developers test a fake build, without a fake uuid + AND NOT QT_SBOM_NO_FAKE_DETERMINISTIC_BUILD_SPDX_IDX_SUFFIX + ) + set(unique_suffix "fake-id-suffix") + else() + string(SHA1 namespace_sha "${arg_SPDX_NAMESPACE}") + + if(arg_HASH_LENGTH) + set(sha_suffix_length "${arg_HASH_LENGTH}") + else() + set(sha_suffix_length "12") + endif() + + string(SUBSTRING "${namespace_sha}" 0 "${sha_suffix_length}" unique_suffix) + endif() + + set(${arg_OUT_VAR_UNIQUE_SUFFIX} "${unique_suffix}" PARENT_SCOPE) +endfunction() + +# Retrieves the current project's spdx id suffix. +function(_qt_internal_sbom_get_spdx_id_unique_suffix out_var) + get_cmake_property(unique_suffix _qt_internal_sbom_repo_spdx_id_unique_suffix) + if(NOT unique_suffix) + set(unique_suffix "") + endif() + + set(${out_var} "${unique_suffix}" PARENT_SCOPE) +endfunction() + # Returns a lower case host platform name for sbom document namespace purposes. function(_qt_internal_sbom_get_host_platform_name out_var) string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" main_value) diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomFileHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomFileHelpers.cmake index f39067d68a..92fd077c4c 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomFileHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomFileHelpers.cmake @@ -52,10 +52,12 @@ function(_qt_internal_sbom_handle_target_binary_files target) THIRD_PARTY_LIBRARY THIRD_PARTY_LIBRARY_WITH_FILES THIRD_PARTY_SOURCES + SBOM_PROJECT EXECUTABLE LIBRARY TRANSLATIONS RESOURCES + BUILD_TOOL CUSTOM CUSTOM_NO_INFIX ) @@ -75,8 +77,10 @@ function(_qt_internal_sbom_handle_target_binary_files target) SYSTEM_LIBRARY THIRD_PARTY_LIBRARY THIRD_PARTY_SOURCES + SBOM_PROJECT TRANSLATIONS RESOURCES + BUILD_TOOL CUSTOM CUSTOM_NO_INFIX ) @@ -797,6 +801,7 @@ function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var) set(is_in_source_dir FALSE) set(is_in_build_dir FALSE) + set(is_in_sysroot_dir FALSE) if(NOT arg_REPO_PROJECT_NAME_LOWERCASE) _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name) @@ -827,6 +832,12 @@ function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var) if(NOT is_in_source_dir AND NOT is_in_build_dir) _qt_internal_path_is_prefix(CMAKE_INSTALL_PREFIX "${path}" is_in_prefix_dir) endif() + if(CMAKE_SYSROOT + AND NOT is_in_source_dir + AND NOT is_in_build_dir + AND NOT is_in_prefix_dir) + _qt_internal_path_is_prefix(CMAKE_SYSROOT "${path}" is_in_sysroot_dir) + endif() else() # We consider relative paths to be relative to the current source dir. set(is_in_source_dir TRUE) @@ -854,6 +865,10 @@ function(_qt_internal_sbom_map_path_to_reproducible_relative_path out_var) set(handled TRUE) set(marker "/install_dir") string(REPLACE "${CMAKE_INSTALL_PREFIX}/" "${marker}/" path_out "${path_in_real}") + elseif(is_in_sysroot_dir) + set(handled TRUE) + set(marker "/sysroot_dir") + string(REPLACE "${CMAKE_SYSROOT}/" "${marker}/" path_out "${path_in_real}") else() # If it's not a source dir, a build dir, or install dir, it might be some kind of # weird genex or marker that we don't handle yet. @@ -1159,6 +1174,8 @@ endfunction() # Get a sanitized spdx id for a file. # For consistency, we prefix the id with SPDXRef-PackagedFile-. This is not a requirement. function(_qt_internal_sbom_get_file_spdx_id target out_var) - _qt_internal_sbom_get_sanitized_spdx_id(spdx_id "SPDXRef-PackagedFile-${target}") + _qt_internal_sbom_get_spdx_id_unique_suffix(spdx_id_unique_suffix) + _qt_internal_sbom_get_sanitized_spdx_id(spdx_id + "SPDXRef-PackagedFile-${target}${spdx_id_unique_suffix}") set(${out_var} "${spdx_id}" PARENT_SCOPE) endfunction() diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationCycloneDXHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationCycloneDXHelpers.cmake index 59797d24b7..44a63f22af 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationCycloneDXHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationCycloneDXHelpers.cmake @@ -85,6 +85,8 @@ serial_number_uuid = \"${arg_BOM_SERIAL_NUMBER_UUID}\" # Required description = '''${project_comment} ''' + + [[project_build_tools]] name = \"cmake\" version = \"${CMAKE_VERSION}\" @@ -92,14 +94,12 @@ component_type = \"application\" description = \"Build system tool used to build the project.\" ") - _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) - _qt_internal_sbom_create_sbom_staging_file( - CONTENT "${content}" - SBOM_FORMAT "CYDX_V1_6" - REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" - OUT_VAR_CREATE_STAGING_FILE create_staging_file - OUT_VAR_SBOM_DIR sbom_dir - ) + set(sbom_format "CYDX_V1_6") + _qt_internal_sbom_save_intro_content( + SBOM_FORMAT "${sbom_format}" + CONTENT "${content}") + + _qt_internal_sbom_create_sbom_staging_dir(OUT_VAR_SBOM_DIR sbom_dir) _qt_internal_sbom_save_project_info_in_global_properties( SUPPLIER "${arg_SUPPLIER}" @@ -113,16 +113,16 @@ description = \"Build system tool used to build the project.\" OUTPUT "${arg_OUTPUT}" OUTPUT_RELATIVE_PATH "${arg_OUTPUT_RELATIVE_PATH}" SBOM_DIR "${sbom_dir}" - PROPERTY_SUFFIX _cydx + SBOM_FORMAT "${sbom_format}" ) - - set_property(GLOBAL APPEND PROPERTY _qt_sbom_cmake_include_files_cydx "${create_staging_file}") endfunction() # Finalizes the CycloneDX sbom generation for a project. function(_qt_internal_sbom_end_project_generate_cyclone) + set(sbom_format "CYDX_V1_6") + _qt_internal_sbom_get_common_path_variables_from_global_properties( - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" OUT_VAR_SBOM_BUILD_OUTPUT_PATH sbom_build_output_path OUT_VAR_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT sbom_build_output_path_without_ext OUT_VAR_SBOM_BUILD_OUTPUT_DIR sbom_build_output_dir @@ -137,18 +137,34 @@ function(_qt_internal_sbom_end_project_generate_cyclone) _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) _qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase) + _qt_internal_get_current_project_sbom_dir(sbom_dir) + + _qt_internal_sbom_handle_project_relationships( + OUTPUT_SBOM_FORMAT "${sbom_format}" + OUT_VAR_RELATIONSHIP_STRINGS relationship_strings + ) + + set(staging_file_args "") + if(relationship_strings) + list(APPEND staging_file_args RELATIONSHIP_STRINGS "${relationship_strings}") + endif() + + _qt_internal_sbom_create_sbom_staging_file( + SBOM_FORMAT "${sbom_format}" + SBOM_DIR "${sbom_dir}" + REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" + ${staging_file_args} + ) # Process licenses before getting the includes. _qt_internal_sbom_add_recorded_licenses_cydx() _qt_internal_sbom_get_cmake_include_files( - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" OUT_VAR_INCLUDES includes OUT_VAR_POST_GENERATION_INCLUDES post_generation_includes ) - _qt_internal_get_current_project_sbom_dir(sbom_dir) - set(build_time_args "") if(includes) list(APPEND build_time_args INCLUDES "${includes}") @@ -157,7 +173,7 @@ function(_qt_internal_sbom_end_project_generate_cyclone) list(APPEND build_time_args POST_GENERATION_INCLUDES "${post_generation_includes}") endif() _qt_internal_sbom_create_build_time_sbom_targets( - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" REAL_QT_REPO_PROJECT_NAME_LOWERCASE "${real_qt_repo_project_name_lowercase}" SBOM_BUILD_OUTPUT_PATH "${sbom_build_output_path}" @@ -169,7 +185,7 @@ function(_qt_internal_sbom_end_project_generate_cyclone) _qt_internal_sbom_setup_multi_config_install_markers( SBOM_DIR "${sbom_dir}" - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" OUT_VAR_EXTRA_CODE_BEGIN extra_code_begin OUT_VAR_EXTRA_CODE_INNER_END extra_code_inner_end @@ -203,7 +219,7 @@ function(_qt_internal_sbom_end_project_generate_cyclone) endif() _qt_internal_sbom_setup_sbom_install_code( - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" SBOM_INSTALL_OUTPUT_PATH "${sbom_install_output_path}" SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT "${sbom_install_output_path_without_ext}" @@ -213,7 +229,7 @@ function(_qt_internal_sbom_end_project_generate_cyclone) ) _qt_internal_sbom_clear_cmake_include_files( - SBOM_FORMAT "CYDX_V1_6" + SBOM_FORMAT "${sbom_format}" ) endfunction() @@ -241,8 +257,8 @@ function(_qt_internal_sbom_generate_cyclone_add_package) # Additions compared to spdx function signature. PURL_VALUES - DEPENDENCIES CYDX_PROPERTIES + SBOM_RELATIONSHIP_ENTRIES ) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) @@ -298,14 +314,21 @@ function(_qt_internal_sbom_generate_cyclone_add_package) set(version_field "version = \\\"${arg_VERSION}\\\"") endif() - set(dependency_field "") - set(dependency_list ${arg_DEPENDENCIES}) - if(dependency_list) - # Wrap values in double quotes. - list(TRANSFORM dependency_list PREPEND "\\\"") - list(TRANSFORM dependency_list APPEND "\\\"") - list(JOIN dependency_list ", " dependency_string) - set(dependency_field "dependencies = [${dependency_string}]") + set(relationships_field "") + if(arg_SBOM_RELATIONSHIP_ENTRIES) + _qt_internal_sbom_serialize_relationship_entries( + OUTPUT_SBOM_FORMAT "CYDX_V1_6" + CYDX_TOML_KEY "components." + ESCAPE_CYDX_QUOTES + OUT_VAR_RELATIONSHIPS_STRINGS entries_relationships_strings + SBOM_RELATIONSHIP_ENTRIES ${arg_SBOM_RELATIONSHIP_ENTRIES} + ) + if(entries_relationships_strings) + # Remove duplicates, because apparently we sometimes get them for some system libraries. + list(REMOVE_DUPLICATES entries_relationships_strings) + + list(JOIN entries_relationships_strings "\n" relationships_field) + endif() endif() set(copyright_field "") @@ -367,8 +390,8 @@ ${external_bom_link_field} ${cpe_field} ${purl_field} ${license_concluded_field} -${dependency_field} ${properties_field} +${relationships_field} \" ) ") diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationHelpers.cmake index 1ade46c950..b8916e3576 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomGenerationHelpers.cmake @@ -141,6 +141,8 @@ PackageVersion: ${QT_SBOM_GIT_VERSION}") set(project_comment "${project_comment}") + _qt_internal_sbom_get_spdx_id_unique_suffix(spdx_id_unique_suffix) + set(content "SPDXVersion: SPDX-2.3 DataLicense: CC0-1.0 @@ -152,20 +154,6 @@ CreatorComment: This SPDX document was created from CMake ${CMAKE_VERSION} build system from https://code.qt.io/cgit/qt/qtbase.git/tree/cmake/QtPublicSbomHelpers.cmake Created: ${current_utc}\${QT_SBOM_EXTERNAL_DOC_REFS} -PackageName: ${CMAKE_CXX_COMPILER_ID} -SPDXID: SPDXRef-compiler -PackageVersion: ${CMAKE_CXX_COMPILER_VERSION} -PackageDownloadLocation: NOASSERTION -PackageLicenseConcluded: NOASSERTION -PackageLicenseDeclared: NOASSERTION -PackageCopyrightText: NOASSERTION -PackageSupplier: Organization: Anonymous -FilesAnalyzed: false -PackageSummary: The compiler as identified by CMake, running on ${CMAKE_HOST_SYSTEM_NAME} (${CMAKE_HOST_SYSTEM_PROCESSOR}) -PrimaryPackagePurpose: APPLICATION -Relationship: SPDXRef-compiler BUILD_DEPENDENCY_OF ${project_spdx_id} -RelationshipComment: ${project_spdx_id} is built by compiler ${CMAKE_CXX_COMPILER_ID} version ${CMAKE_CXX_COMPILER_VERSION} - PackageName: ${arg_PROJECT} SPDXID: ${project_spdx_id}${fields} ExternalRef: PACKAGE-MANAGER purl pkg:generic/${arg_SUPPLIER}/${arg_PROJECT}@${QT_SBOM_GIT_VERSION} @@ -178,19 +166,14 @@ PackageHomePage: ${arg_SUPPLIER_URL} PackageComment: ${project_comment} FilesAnalyzed: false BuiltDate: ${current_utc} -Relationship: SPDXRef-DOCUMENT DESCRIBES ${project_spdx_id} -") +Relationship: SPDXRef-DOCUMENT DESCRIBES ${project_spdx_id}") - _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) - _qt_internal_sbom_create_sbom_staging_file( - CONTENT "${content}" - SBOM_FORMAT "SPDX_V2" - REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" - OUT_VAR_CREATE_STAGING_FILE create_staging_file - OUT_VAR_SBOM_DIR sbom_dir - ) + set(sbom_format "SPDX_V2") + _qt_internal_sbom_save_intro_content( + SBOM_FORMAT "${sbom_format}" + CONTENT "${content}") - set_property(GLOBAL APPEND PROPERTY _qt_internal_sbom_dirs "${sbom_dir}") + _qt_internal_sbom_create_sbom_staging_dir(OUT_VAR_SBOM_DIR sbom_dir) _qt_internal_sbom_save_project_info_in_global_properties( SUPPLIER "${arg_SUPPLIER}" @@ -198,16 +181,16 @@ Relationship: SPDXRef-DOCUMENT DESCRIBES ${project_spdx_id} NAMESPACE "${arg_NAMESPACE}" PROJECT "${arg_PROJECT}" PROJECT_SPDX_ID "${project_spdx_id}" + EXTERNAL_REFERENCE_SBOM_DIRS "${sbom_dir}" ) _qt_internal_sbom_save_common_path_variables_in_global_properties( OUTPUT "${arg_OUTPUT}" OUTPUT_RELATIVE_PATH "${arg_OUTPUT_RELATIVE_PATH}" SBOM_DIR "${sbom_dir}" + SBOM_FORMAT "${sbom_format}" ) - set_property(GLOBAL APPEND PROPERTY _qt_sbom_cmake_include_files "${create_staging_file}") - set_property(GLOBAL PROPERTY _qt_sbom_spdx_id_count 0) set_property(GLOBAL PROPERTY _qt_sbom_relationship_counter 0) endfunction() @@ -216,8 +199,9 @@ endfunction() # Creates an 'sbom' custom target to generate an incomplete sbom at build time (no checksums). # Creates install rules to install a complete (with checksums) sbom. function(_qt_internal_sbom_end_project_generate) + set(sbom_format "SPDX_V2") _qt_internal_sbom_get_common_path_variables_from_global_properties( - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" OUT_VAR_SBOM_BUILD_OUTPUT_PATH sbom_build_output_path OUT_VAR_SBOM_BUILD_OUTPUT_PATH_WITHOUT_EXT sbom_build_output_path_without_ext OUT_VAR_SBOM_BUILD_OUTPUT_DIR sbom_build_output_dir @@ -232,9 +216,27 @@ function(_qt_internal_sbom_end_project_generate) _qt_internal_sbom_get_root_project_name_lower_case(repo_project_name_lowercase) _qt_internal_sbom_get_qt_repo_project_name_lower_case(real_qt_repo_project_name_lowercase) + _qt_internal_get_current_project_sbom_dir(sbom_dir) + + _qt_internal_sbom_handle_project_relationships( + OUTPUT_SBOM_FORMAT "${sbom_format}" + OUT_VAR_RELATIONSHIP_STRINGS relationship_strings + ) + + set(staging_file_args "") + if(relationship_strings) + list(APPEND staging_file_args RELATIONSHIP_STRINGS "${relationship_strings}") + endif() + + _qt_internal_sbom_create_sbom_staging_file( + SBOM_FORMAT "${sbom_format}" + SBOM_DIR "${sbom_dir}" + REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" + ${staging_file_args} + ) _qt_internal_sbom_get_cmake_include_files( - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" OUT_VAR_INCLUDES includes OUT_VAR_BEFORE_CHECKSUM_INCLUDES before_checksum_includes OUT_VAR_AFTER_CHECKSUM_INCLUDES after_checksum_includes @@ -242,8 +244,6 @@ function(_qt_internal_sbom_end_project_generate) OUT_VAR_VERIFY_INCLUDES verify_includes ) - _qt_internal_get_current_project_sbom_dir(sbom_dir) - set(build_time_args "") if(includes) list(APPEND build_time_args INCLUDES "${includes}") @@ -252,7 +252,7 @@ function(_qt_internal_sbom_end_project_generate) list(APPEND build_time_args POST_GENERATION_INCLUDES "${post_generation_includes}") endif() _qt_internal_sbom_create_build_time_sbom_targets( - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" REAL_QT_REPO_PROJECT_NAME_LOWERCASE "${real_qt_repo_project_name_lowercase}" SBOM_BUILD_OUTPUT_PATH "${sbom_build_output_path}" @@ -280,7 +280,7 @@ function(_qt_internal_sbom_end_project_generate) _qt_internal_sbom_setup_multi_config_install_markers( SBOM_DIR "${sbom_dir}" - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" OUT_VAR_EXTRA_CODE_BEGIN extra_code_begin OUT_VAR_EXTRA_CODE_INNER_END extra_code_inner_end @@ -335,7 +335,7 @@ unset(_verification_code) endif() _qt_internal_sbom_setup_sbom_install_code( - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" REPO_PROJECT_NAME_LOWERCASE "${repo_project_name_lowercase}" SBOM_INSTALL_OUTPUT_PATH "${sbom_install_output_path}" SBOM_INSTALL_OUTPUT_PATH_WITHOUT_EXT "${sbom_install_output_path_without_ext}" @@ -346,7 +346,7 @@ unset(_verification_code) ) _qt_internal_sbom_clear_cmake_include_files( - SBOM_FORMAT "SPDX_V2" + SBOM_FORMAT "${sbom_format}" ) endfunction() @@ -529,22 +529,29 @@ Relationship: ${arg_RELATIONSHIP} set_property(GLOBAL APPEND PROPERTY _qt_sbom_cmake_include_files "${file_sbom_to_install}") endfunction() -# Helper to add a reference to an external SPDX document. +# Helper to add a reference to an external SPDX v2 document. # # EXTERNAL_DOCUMENT_SPDX_ID: The spdx id by which the external document should be referenced in # the current project SPDX document. This semantically serves as a pointer to the external document # URI. # e.g. DocumentRef-qtbase. # -# EXTERNAL_DOCUMENT_FILE_PATH: The relative file path of the external sbom document. -# e.g. "sbom/qtbase-6.9.0.spdx" +# SBOM_FORMAT: Type of SPDX file, SPDX_V2_TAG_VALUE or SPDX_V2_JSON. # +# EXTERNAL_DOCUMENT_NAMESPACE: Explicit SPDX namespace to embed, instead of parsing the file passed +# in EXTERNAL_DOCUMENT_FILE_PATH. +# +# EXTERNAL_DOCUMENT_SHA1: Explicit sha1 to embed, instead of calculating it from the file passed +# in EXTERNAL_DOCUMENT_FILE_PATH. +# +# EXTERNAL_DOCUMENT_FILE_PATH: An absolute or relative file path of the external sbom document. +# In case of a relative file path, it will be searched for in the directories specified by the +# EXTERNAL_DOCUMENT_INSTALL_PREFIXES option. +# e.g. "sbom/qtbase-6.9.0.spdx" # Can contain generator expressions. -# The file path is searched for in the directories specified by the -# EXTERNAL_DOCUMENT_INSTALL_PREFIXES option during sbom generation, to compute the file checksum. -# The file path is NOT embedded into the current project spdx document. -# Only its spdx id and namespace is embedded. The namespace is extracted from the contents of the -# referenced file. +# The file path is NOT embedded into the current project spdx document. Only the document ref id, +# spdx namespace and sha1 is embedded. +# The namespace is extracted from the contents of the referenced file. # # EXTERNAL_DOCUMENT_INSTALL_PREFIXES: A list of directories where the external document file path # is searched for. The first existing file is used. Additionally the following locations are @@ -571,6 +578,10 @@ function(_qt_internal_sbom_generate_add_external_reference) EXTERNAL_DOCUMENT_SPDX_ID EXTERNAL_PACKAGE_SPDX_ID RELATIONSHIP_STRING + + EXTERNAL_DOCUMENT_NAMESPACE + EXTERNAL_DOCUMENT_SHA1 + SBOM_FORMAT ) set(multi_args EXTERNAL_DOCUMENT_INSTALL_PREFIXES @@ -578,7 +589,46 @@ function(_qt_internal_sbom_generate_add_external_reference) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) - _qt_internal_sbom_set_default_option_value_and_error_if_empty(EXTERNAL_DOCUMENT_FILE_PATH "") + # Default to tag:value if nothing is passed, because that was the previous behavior before this + # option got introduced. + if(NOT arg_SBOM_FORMAT) + set(arg_SBOM_FORMAT "SPDX_V2_TAG_VALUE") + endif() + + if(NOT arg_EXTERNAL_DOCUMENT_FILE_PATH AND NOT arg_EXTERNAL_DOCUMENT_NAMESPACE) + message(FATAL_ERROR "Either EXTERNAL_DOCUMENT_FILE_PATH or " + "EXTERNAL_DOCUMENT_NAMESPACE together with EXTERNAL_DOCUMENT_SHA1 must be specified " + "to be able to add an external reference for an external SPDX v2 tag:value document.") + endif() + + set(debug_var_assignments " + EXTERNAL_DOCUMENT_FILE_PATH: '${arg_EXTERNAL_DOCUMENT_FILE_PATH}' + EXTERNAL_DOCUMENT_NAMESPACE: '${arg_EXTERNAL_DOCUMENT_NAMESPACE}' + EXTERNAL_DOCUMENT_SHA1: '${arg_EXTERNAL_DOCUMENT_SHA1}' + EXTERNAL_DOCUMENT_SPDX_ID: '${arg_EXTERNAL_DOCUMENT_SPDX_ID}' +") + + if(NOT arg_EXTERNAL_DOCUMENT_FILE_PATH + AND arg_EXTERNAL_DOCUMENT_NAMESPACE + AND NOT arg_EXTERNAL_DOCUMENT_SHA1) + message(FATAL_ERROR + "EXTERNAL_DOCUMENT_SHA1 must be specified if EXTERNAL_DOCUMENT_NAMESPACE is specified " + "and EXTERNAL_DOCUMENT_FILE_PATH is not specified.\n${debug_var_assignments}") + endif() + + if(NOT arg_EXTERNAL_DOCUMENT_FILE_PATH + AND NOT arg_EXTERNAL_DOCUMENT_NAMESPACE + AND arg_EXTERNAL_DOCUMENT_SHA1) + message(FATAL_ERROR + "EXTERNAL_DOCUMENT_NAMESPACE must be specified if EXTERNAL_DOCUMENT_SHA1 is specified " + "and EXTERNAL_DOCUMENT_FILE_PATH is not specified.\n${debug_var_assignments}") + endif() + + if(arg_EXTERNAL_DOCUMENT_FILE_PATH) + set(find_external_document TRUE) + else() + set(find_external_document FALSE) + endif() if(NOT arg_EXTERNAL_DOCUMENT_SPDX_ID) get_property(spdx_id_count GLOBAL PROPERTY _qt_sbom_spdx_id_count) @@ -594,7 +644,8 @@ function(_qt_internal_sbom_generate_add_external_reference) if(NOT sbom_project_spdx_id) message(FATAL_ERROR "Call _qt_internal_sbom_begin_project() first") endif() - if(arg_RELATIONSHIP_STRING STREQUAL "") + + if(NOT arg_RELATIONSHIP_STRING) if(arg_EXTERNAL_PACKAGE_SPDX_ID) set(external_package "${arg_EXTERNAL_DOCUMENT_SPDX_ID}:${arg_EXTERNAL_PACKAGE_SPDX_ID}") set(arg_RELATIONSHIP_STRING @@ -608,43 +659,23 @@ function(_qt_internal_sbom_generate_add_external_reference) _qt_internal_get_staging_area_spdx_file_path(staging_area_spdx_file) - set(install_prefixes "") + set(document_search_paths "") + if(find_external_document) + set(search_path_args "") + if(arg_EXTERNAL_DOCUMENT_INSTALL_PREFIXES) + list(APPEND search_path_args + EXTERNAL_DOCUMENT_SEARCH_PATHS ${arg_EXTERNAL_DOCUMENT_INSTALL_PREFIXES} + ) + endif() - # Add the current sbom build dirs as install prefixes, so that we can use ninja 'sbom' - # in top-level builds. This is needed because the external references will point - # to sbom docs in different build dirs, not just one. - # We also need it in case we are converting a json document to a tag/value format in the - # current build dir of the project, and want it to be found. - get_cmake_property(build_sbom_dirs _qt_internal_sbom_dirs) - if(build_sbom_dirs) - foreach(build_sbom_dir IN LISTS build_sbom_dirs) - list(APPEND install_prefixes "${build_sbom_dir}") - endforeach() + _qt_internal_sbom_get_external_reference_search_paths(document_search_paths + SEARCH_IN_BUILD_SBOM_DIRS + SEARCH_IN_QT_PREFIXES + SEARCH_IN_DESTDIR_INSTALL_PREFIX_AT_INSTALL_TIME + ${search_path_args} + ) endif() - # Always append the install time install prefix. - # The variable is escaped, so it is evaluated during cmake install time, so that the value - # can be overridden with cmake --install . --prefix . - list(APPEND install_prefixes "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}") - - if(arg_EXTERNAL_DOCUMENT_INSTALL_PREFIXES) - list(APPEND install_prefixes ${arg_EXTERNAL_DOCUMENT_INSTALL_PREFIXES}) - endif() - - if(QT6_INSTALL_PREFIX) - list(APPEND install_prefixes ${QT6_INSTALL_PREFIX}) - endif() - - if(QT_ADDITIONAL_PACKAGES_PREFIX_PATH) - list(APPEND install_prefixes ${QT_ADDITIONAL_PACKAGES_PREFIX_PATH}) - endif() - - if(QT_ADDITIONAL_SBOM_DOCUMENT_PATHS) - list(APPEND install_prefixes ${QT_ADDITIONAL_SBOM_DOCUMENT_PATHS}) - endif() - - list(REMOVE_DUPLICATES install_prefixes) - set(relationship_content "") if(arg_RELATIONSHIP_STRING) set(relationship_content " @@ -655,29 +686,40 @@ function(_qt_internal_sbom_generate_add_external_reference) # File path may not exist yet, and it could be a generator expression. set(content " - set(relative_file_name \"${arg_EXTERNAL_DOCUMENT_FILE_PATH}\") - set(document_dir_paths ${install_prefixes}) - list(JOIN document_dir_paths \"\\n\" document_dir_paths_per_line) - foreach(document_dir_path IN LISTS document_dir_paths) - set(document_file_path \"\${document_dir_path}/\${relative_file_name}\") - if(EXISTS \"\${document_file_path}\") - break() - endif() - endforeach() - if(NOT EXISTS \"\${document_file_path}\") - message(FATAL_ERROR \"Could not find external SBOM document \${relative_file_name}\" - \" in any of the document dir paths: \${document_dir_paths_per_line} \" + set(find_external_document \"${find_external_document}\") + set(document_search_paths \"${document_search_paths}\") + set(maybe_external_document_file_path \"${arg_EXTERNAL_DOCUMENT_FILE_PATH}\") + set(sbom_format \"${arg_SBOM_FORMAT}\") + + set(explicit_external_document_namespace \"${arg_EXTERNAL_DOCUMENT_NAMESPACE}\") + set(explicit_external_document_sha1 \"${arg_EXTERNAL_DOCUMENT_SHA1}\") + + # The helper functions below are used both during configure time and SBOM generation + # time. During configure time, QT_GENERATE_SBOM is checked to return early gracefully, + # to allow projects to skip SBOM generation. + # During SBOM generation time, we need to ensure these functions run properly. + # Backup the var instead of setting it directly, because some of the testing infrastructure + # does checks of the variable at the end of sbom generation. + set(backup_qt_generate_sbom \"${QT_GENERATE_SBOM}\") + set(QT_GENERATE_SBOM ON) + if(find_external_document) + _qt_internal_sbom_find_external_reference_document(document_file_path + EXTERNAL_DOCUMENT_FILE_PATH \"\${maybe_external_document_file_path}\" + EXTERNAL_DOCUMENT_SEARCH_PATHS \${document_search_paths} ) - endif() - file(SHA1 \"\${document_file_path}\" ext_sha1) - file(READ \"\${document_file_path}\" ext_content) - if(NOT \"\${ext_content}\" MATCHES \"[\\r\\n]DocumentNamespace:\") - message(FATAL_ERROR \"Missing DocumentNamespace in \${document_file_path}\") - endif() + _qt_internal_sbom_parse_spdx_v2_document_namespace( + EXTERNAL_DOCUMENT_FILE_PATH \"\${document_file_path}\" + SBOM_FORMAT \"\${sbom_format}\" + OUT_VAR_DOCUMENT_NAMESPACE ext_ns + ) - string(REGEX REPLACE \"^.*[\\r\\n]DocumentNamespace:[ \\t]*([^#\\r\\n]*).*$\" - \"\\\\1\" ext_ns \"\${ext_content}\") + file(SHA1 \"\${document_file_path}\" ext_sha1) + else() + set(ext_ns \"\${explicit_external_document_namespace}\") + set(ext_sha1 \"\${explicit_external_document_sha1}\") + endif() + set(QT_GENERATE_SBOM \${backup_qt_generate_sbom}) string(APPEND QT_SBOM_EXTERNAL_DOC_REFS \" ExternalDocumentRef: ${arg_EXTERNAL_DOCUMENT_SPDX_ID} \${ext_ns} SHA1: \${ext_sha1}\") @@ -699,12 +741,12 @@ function(_qt_internal_sbom_generate_add_package) ) set(single_args PACKAGE + PACKAGE_SUMMARY VERSION LICENSE_DECLARED LICENSE_CONCLUDED COPYRIGHT DOWNLOAD_LOCATION - RELATIONSHIP SPDXID SUPPLIER PURPOSE @@ -713,6 +755,8 @@ function(_qt_internal_sbom_generate_add_package) set(multi_args EXTREF CPE + RELATIONSHIPS # Deprecated, SBOM_RELATIONSHIP_ENTRIES is preferred + SBOM_RELATIONSHIP_ENTRIES ) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") _qt_internal_validate_all_args_are_parsed(arg) @@ -776,6 +820,12 @@ PackageCopyrightText: NOASSERTION" ) endif() + if(arg_PACKAGE_SUMMARY) + set(fields "${fields} +PackageSummary: ${arg_PACKAGE_SUMMARY}" + ) + endif() + if(arg_PURPOSE) set(fields "${fields} PrimaryPackagePurpose: ${arg_PURPOSE}" @@ -802,12 +852,33 @@ ExternalRef: SECURITY cpe23Type ${cpe}" if(NOT sbom_project_spdx_id) message(FATAL_ERROR "Call _qt_internal_sbom_begin_project() first") endif() - if(NOT arg_RELATIONSHIP) - set(arg_RELATIONSHIP "${sbom_project_spdx_id} CONTAINS ${arg_SPDXID}") - else() - string(REPLACE "@QT_SBOM_LAST_SPDXID@" "${arg_SPDXID}" arg_RELATIONSHIP "${arg_RELATIONSHIP}") + + set(relationship_strings "") + if(arg_SBOM_RELATIONSHIP_ENTRIES) + _qt_internal_sbom_serialize_relationship_entries( + OUTPUT_SBOM_FORMAT "SPDX_V2" + OUT_VAR_RELATIONSHIPS_STRINGS entries_relationships_strings + SBOM_RELATIONSHIP_ENTRIES ${arg_SBOM_RELATIONSHIP_ENTRIES} + ) + if(entries_relationships_strings) + list(APPEND relationship_strings ${entries_relationships_strings}) + endif() endif() + # TODO: This is deprecated, SBOM_RELATIONSHIP_ENTRIES is preferred, remove it once qtwebengine + # is ported over. + if(arg_RELATIONSHIPS) + string(REPLACE + "@QT_SBOM_LAST_SPDXID@" "${arg_SPDXID}" arg_RELATIONSHIPS "${arg_RELATIONSHIPS}") + list(APPEND relationship_strings ${arg_RELATIONSHIPS}) + endif() + + # Remove duplicates, because apparently we sometimes get them for some system libraries. + list(REMOVE_DUPLICATES relationship_strings) + + list(JOIN relationship_strings "\n" relationships_str) + string(PREPEND relationships_str "\n") + set(fields "${fields}\\\${QT_SBOM_VERIFICATION_CODE_${arg_SPDXID}}") _qt_internal_get_staging_area_spdx_file_path(staging_area_spdx_file) @@ -824,8 +895,7 @@ SPDXID: ${arg_SPDXID} PackageDownloadLocation: ${arg_DOWNLOAD_LOCATION} PackageVersion: ${arg_VERSION} PackageSupplier: ${arg_SUPPLIER}${fields} -FilesAnalyzed: \\\${QT_SBOM_PACKAGE_HAS_FILES_${arg_SPDXID}} -Relationship: ${arg_RELATIONSHIP} +FilesAnalyzed: \\\${QT_SBOM_PACKAGE_HAS_FILES_${arg_SPDXID}}${relationships_str} \" ) ") diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomHelpers.cmake index 19d3a207d7..3578b0def4 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomHelpers.cmake @@ -31,6 +31,9 @@ function(_qt_internal_sbom_begin_project) USE_GIT_VERSION __QT_INTERNAL_HANDLE_QT_REPO NO_AUTO_DOCUMENT_NAMESPACE_INFIX + NO_AUTO_SEARCH_EXTERNAL_DOCUMENTS_IN_CMAKE_PATHS + NO_AUTO_SPDX_ID_SUFFIX + NO_AUTO_ADD_BUILD_TOOLS ) set(single_args INSTALL_PREFIX @@ -43,6 +46,8 @@ function(_qt_internal_sbom_begin_project) DOCUMENT_NAMESPACE_INFIX DOCUMENT_NAMESPACE_SUFFIX DOCUMENT_NAMESPACE_URL_PREFIX + SPDX_ID_SUFFIX + SPDX_ID_SUFFIX_HASH_LENGTH VERSION SBOM_PROJECT_NAME QT_REPO_PROJECT_NAME @@ -52,6 +57,7 @@ function(_qt_internal_sbom_begin_project) set(multi_args COPYRIGHTS LICENSE_DIR_PATHS + EXTERNAL_DOCUMENT_SEARCH_PATHS ) cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -123,6 +129,20 @@ function(_qt_internal_sbom_begin_project) endif() endif() + if(arg_EXTERNAL_DOCUMENT_SEARCH_PATHS) + set_property(GLOBAL APPEND PROPERTY _qt_internal_sbom_external_document_search_paths + ${arg_EXTERNAL_DOCUMENT_SEARCH_PATHS}) + endif() + + if(arg_NO_AUTO_SEARCH_EXTERNAL_DOCUMENTS_IN_CMAKE_PATHS) + set(auto_search_external_documents_in_cmake_paths FALSE) + else() + set(auto_search_external_documents_in_cmake_paths TRUE) + endif() + set_property(GLOBAL PROPERTY + _qt_internal_sbom_auto_search_external_documents_in_paths + "${auto_search_external_documents_in_cmake_paths}") + if(arg_DOCUMENT_NAMESPACE) set(repo_spdx_namespace "${arg_DOCUMENT_NAMESPACE}") @@ -186,15 +206,41 @@ function(_qt_internal_sbom_begin_project) ) endif() - if(QT_SBOM_GENERATE_CYDX_V1_6) - _qt_internal_sbom_get_cyclone_bom_serial_number( + _qt_internal_sbom_get_cyclone_bom_serial_number( + SPDX_NAMESPACE "${repo_spdx_namespace}" + OUT_VAR_UUID cyclone_dx_bom_serial_number_uuid + ) + list(APPEND begin_project_generate_args_cydx + BOM_SERIAL_NUMBER_UUID "${cyclone_dx_bom_serial_number_uuid}") + + if(QT_SBOM_SPDX_ID_SUFFIX) + set(spdx_id_unique_suffix "-${QT_SBOM_SPDX_ID_SUFFIX}") + elseif(arg_SPDX_ID_SUFFIX) + set(spdx_id_unique_suffix "-${arg_SPDX_ID_SUFFIX}") + elseif(NOT arg_NO_AUTO_SPDX_ID_SUFFIX AND NOT QT_SBOM_NO_AUTO_SPDX_SUFFIX) + set(compute_unique_spdx_id_suffix_args "") + + if(QT_SBOM_SPDX_ID_SUFFIX_HASH_LENGTH) + list(APPEND compute_unique_spdx_id_suffix_args + HASH_LENGTH "${QT_SBOM_SPDX_ID_SUFFIX_HASH_LENGTH}") + elseif(arg_SPDX_ID_SUFFIX_HASH_LENGTH) + list(APPEND compute_unique_spdx_id_suffix_args + HASH_LENGTH "${arg_SPDX_ID_SUFFIX_HASH_LENGTH}") + endif() + + _qt_internal_sbom_compute_uniqueish_spdx_id_suffix( SPDX_NAMESPACE "${repo_spdx_namespace}" - OUT_VAR_UUID cyclone_dx_bom_serial_number_uuid + OUT_VAR_UNIQUE_SUFFIX spdx_id_unique_suffix + ${compute_unique_spdx_id_suffix_args} ) - list(APPEND begin_project_generate_args_cydx - BOM_SERIAL_NUMBER_UUID "${cyclone_dx_bom_serial_number_uuid}") + string(PREPEND spdx_id_unique_suffix "-") + else() + set(spdx_id_unique_suffix "") endif() + set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_spdx_id_unique_suffix + "${spdx_id_unique_suffix}") + if(arg_INSTALL_SBOM_DIR) set(install_sbom_dir "${arg_INSTALL_SBOM_DIR}") elseif(INSTALL_SBOMDIR) @@ -231,9 +277,22 @@ function(_qt_internal_sbom_begin_project) _qt_internal_path_join(repo_spdx_relative_install_path_spdx "${install_sbom_dir}" "${repo_project_file_name_spdx}") + + # Currently only used for exporting as a target's property. + _qt_internal_path_join(repo_spdx_relative_install_path_spdx_json + "${install_sbom_dir}" "${repo_project_file_name_spdx}.json") + + # This is actually the path to the intermediate CycloneDX toml file. _qt_internal_path_join(repo_spdx_relative_install_path_cydx "${install_sbom_dir}" "${repo_project_file_name_cydx}") + # Compute the relative path to the final cydx json file, to be exported in a target's property. + get_filename_component(repo_project_file_name_cydx_without_ext + "${repo_project_file_name_cydx}" NAME_WLE) + + _qt_internal_path_join(repo_spdx_relative_install_path_cydx_json + "${install_sbom_dir}" "${repo_project_file_name_cydx_without_ext}.json") + # Prepend DESTDIR, to allow relocating installed sbom. Needed for CI. _qt_internal_path_join(repo_spdx_install_path_spdx "\$ENV{DESTDIR}${install_prefix}" "${repo_spdx_relative_install_path_spdx}") @@ -353,9 +412,20 @@ function(_qt_internal_sbom_begin_project) set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid "${cyclone_dx_bom_serial_number_uuid}") + # TODO: Figure out what needs to be done to fully port usage to the tag value var below, + # taking into account compatibility for Qt Creator, etc. set_property(GLOBAL PROPERTY _qt_internal_sbom_relative_installed_repo_document_path "${repo_spdx_relative_install_path_spdx}") + set_property(GLOBAL PROPERTY _qt_internal_sbom_document_spdx_v2_tag_value_relative_path + "${repo_spdx_relative_install_path_spdx}") + + set_property(GLOBAL PROPERTY _qt_internal_sbom_document_spdx_v2_json_relative_path + "${repo_spdx_relative_install_path_spdx_json}") + + set_property(GLOBAL PROPERTY _qt_internal_sbom_document_cydx_v1_6_json_relative_path + "${repo_spdx_relative_install_path_cydx_json}") + set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_project_name_lowercase "${repo_project_name_lowercase}") @@ -365,6 +435,8 @@ function(_qt_internal_sbom_begin_project) set_property(GLOBAL PROPERTY _qt_internal_sbom_project_spdx_id "${repo_project_spdx_id}") + _qt_internal_create_project_sbom_target() + # Collect project licenses. set(license_dirs "") @@ -413,6 +485,10 @@ function(_qt_internal_sbom_begin_project) set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_begin_called TRUE) _qt_internal_sbom_setup_project_ops() + + if(NOT arg_NO_AUTO_ADD_BUILD_TOOLS) + _qt_internal_sbom_add_project_default_build_tools() + endif() endfunction() # Check various internal options to decide which sbom generation operations should be setup. @@ -774,9 +850,13 @@ function(_qt_internal_sbom_end_project) set_property(GLOBAL PROPERTY _qt_known_external_documents "") foreach(external_document IN LISTS known_external_documents) set_property(GLOBAL PROPERTY _qt_known_external_documents_${external_document} "") + set_property(GLOBAL PROPERTY _qt_known_external_documents_${external_document}_target "") endforeach() set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_begin_called FALSE) + set_property(GLOBAL PROPERTY _qt_internal_sbom_repo_spdx_id_unique_suffix "") + set_property(GLOBAL PROPERTY _qt_internal_sbom_external_document_search_paths "") + set_property(GLOBAL PROPERTY _qt_internal_sbom_auto_search_external_documents_in_paths "") # Add configure-time dependency on project attribution files. get_property(attribution_files GLOBAL PROPERTY _qt_internal_project_attribution_files) @@ -937,6 +1017,7 @@ macro(_qt_internal_get_sbom_add_target_common_options opt_args single_args multi NO_DEFAULT_QT_SUPPLIER SBOM_INCOMPLETE_3RD_PARTY_DEPENDENCIES IS_QT_3RD_PARTY_HEADER_MODULE + IS_EXTERNAL_SBOM_ENTITY USE_ATTRIBUTION_FILES CREATE_SBOM_FOR_EACH_ATTRIBUTION __QT_INTERNAL_HANDLE_QT_ENTITY_TYPE_PACKAGE_VERSION @@ -948,9 +1029,12 @@ macro(_qt_internal_get_sbom_add_target_common_options opt_args single_args multi __QT_INTERNAL_HANDLE_QT_ENTITY_ATTRIBUTION_FILES ) set(${single_args} + SPDX_ID + EXTERNAL_SBOM_DOCUMENT_TARGET DEFAULT_SBOM_ENTITY_TYPE SBOM_ENTITY_TYPE PACKAGE_VERSION + PACKAGE_SUMMARY FRIENDLY_PACKAGE_NAME SUPPLIER CPE_VENDOR @@ -970,6 +1054,9 @@ macro(_qt_internal_get_sbom_add_target_common_options opt_args single_args multi ATTRIBUTION_FILE_PATHS ATTRIBUTION_FILE_DIR_PATHS ATTRIBUTION_IDS + SBOM_RELATIONSHIP_ENTRIES + # deprecated, previously used for SPDX v2 string-ified relationships + # still used by WebEngine. SBOM_RELATIONSHIPS ) @@ -1114,13 +1201,7 @@ function(_qt_internal_sbom_add_target target) string(APPEND package_comment "Contained in CMake package: ${qt_package_name}\n") endif() - # Record the target spdx id right now, so we can refer to it in later attribution targets - # if needed. - _qt_internal_sbom_record_target_spdx_id(${target} - SBOM_ENTITY_TYPE "${sbom_entity_type}" - PACKAGE_NAME "${package_name_for_spdx_id}" - OUT_VAR package_spdx_id - ) + _qt_internal_sbom_get_spdx_id_for_target("${target}" package_spdx_id) if(arg_USE_ATTRIBUTION_FILES) set(attribution_args @@ -1471,35 +1552,39 @@ function(_qt_internal_sbom_add_target target) list(APPEND project_package_options_cydx COMMENT "\n${package_comment}") endif() - _qt_internal_sbom_handle_target_dependencies("${target}" - SPDX_ID "${package_spdx_id}" - LIBRARIES "${arg_LIBRARIES}" - PUBLIC_LIBRARIES "${arg_PUBLIC_LIBRARIES}" - OUT_CYDX_DEPENDENCIES cydx_dependencies - OUT_SPDX_RELATIONSHIPS spdx_relationships - OUT_EXTERNAL_TARGET_DEPENDENCIES external_target_dependencies - ) - if(cydx_dependencies) - list(APPEND project_package_options_cydx DEPENDENCIES ${cydx_dependencies}) - endif() - - # These are processed at the end of document generation. - if(external_target_dependencies) - _qt_internal_sbom_record_external_target_dependecies( - TARGETS ${external_target_dependencies} - ) - endif() - get_cmake_property(project_spdx_id _qt_internal_sbom_project_spdx_id) - list(APPEND spdx_relationships "${project_spdx_id} CONTAINS ${package_spdx_id}") - if(arg_SBOM_RELATIONSHIPS) - list(APPEND spdx_relationships "${arg_SBOM_RELATIONSHIPS}") + _qt_internal_forward_function_args( + FORWARD_PREFIX arg + FORWARD_OUT_VAR relationship_args + FORWARD_MULTI + LIBRARIES + PUBLIC_LIBRARIES + SBOM_DEPENDENCIES + SBOM_RELATIONSHIP_ENTRIES + SBOM_RELATIONSHIPS # deprecated, still used by WebEngine + ) + + _qt_internal_sbom_handle_target_relationships("${target}" + SPDX_ID "${package_spdx_id}" + PROJECT_SPDX_ID "${project_spdx_id}" + ${relationship_args} + OUT_VAR_SBOM_RELATIONSHIP_ENTRIES sbom_relationship_entries + OUT_VAR_SPDX_V2_RELATIONSHIPS spdx_relationships # deprecated, still used by WebEngine + ) + if(sbom_relationship_entries) + list(APPEND project_package_options_cydx + SBOM_RELATIONSHIP_ENTRIES ${sbom_relationship_entries}) + list(APPEND project_package_options_spdx + SBOM_RELATIONSHIP_ENTRIES ${sbom_relationship_entries}) + endif() + if(spdx_relationships) + list(APPEND project_package_options_spdx RELATIONSHIPS ${spdx_relationships}) endif() - list(REMOVE_DUPLICATES spdx_relationships) - list(JOIN spdx_relationships "\nRelationship: " relationships) - list(APPEND project_package_options_spdx RELATIONSHIP "${relationships}") + if(arg_PACKAGE_SUMMARY) + list(APPEND project_package_options_spdx PACKAGE_SUMMARY "${arg_PACKAGE_SUMMARY}") + endif() if(QT_SBOM_GENERATE_SPDX_V2) _qt_internal_sbom_generate_add_package( @@ -1604,9 +1689,7 @@ function(_qt_internal_add_sbom target) return() endif() - set(opt_args - IMMEDIATE_FINALIZATION - ) + set(opt_args "") set(single_args "") set(multi_args "") cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -1619,10 +1702,6 @@ function(_qt_internal_add_sbom target) _qt_internal_create_sbom_target("${target}" ${forward_args}) endif() - if(arg_IMMEDIATE_FINALIZATION) - list(APPEND forward_args IMMEDIATE_FINALIZATION) - endif() - # Save the passed options. _qt_internal_extend_sbom("${target}" ${forward_args}) endfunction() @@ -1654,9 +1733,99 @@ function(_qt_internal_create_sbom_target target) ) endfunction() +# Creates a custom target to represent a project's root SBOM package / component. +# For SPDX it represents what we consider the root package, although the spec doesn't define +# any such package. +# For CYDX it represents the root component, which is defined by the spec. +# The target is currently intended to be used in sbom relationship entries, but might be expanded +# with further information. +function(_qt_internal_create_project_sbom_target) + if(NOT QT_GENERATE_SBOM) + return() + endif() + + set(opt_args "") + set(single_args "") + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + _qt_internal_sbom_get_current_project_target(target) + if(TARGET "${target}") + message(FATAL_ERROR "The target ${target} already exists.") + endif() + + add_library("${target}" INTERFACE IMPORTED) + + get_property(project_spdx_id GLOBAL PROPERTY _qt_internal_sbom_project_spdx_id) + if(NOT project_spdx_id) + message(FATAL_ERROR "The global property _qt_internal_sbom_project_spdx_id was not set, " + "which is required to create a project sbom target.") + endif() + + get_property(repo_document_namespace + GLOBAL PROPERTY _qt_internal_sbom_repo_document_namespace) + + if(NOT repo_document_namespace) + message(FATAL_ERROR "The global property _qt_internal_sbom_repo_document_namespace was not" + " set, which is required to create a project sbom target.") + endif() + + get_property(bom_serial_number_uuid + GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid) + + if(NOT bom_serial_number_uuid) + message(FATAL_ERROR "The global property " + "_qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid" + " was not set, which is required to create a project sbom target.") + endif() + + _qt_internal_sbom_compute_external_document_ref_spdx_id( + "${arg_PROJECT_NAME}" external_document_ref) + + set_target_properties("${target}" PROPERTIES + IMPORTED_GLOBAL TRUE + + _qt_sbom_is_custom_sbom_target "TRUE" + _qt_sbom_is_project_sbom_target "TRUE" + + _qt_sbom_spdx_id "${project_spdx_id}" + _qt_sbom_entity_type "SBOM_PROJECT" + _qt_sbom_spdx_repo_document_namespace "${repo_document_namespace}" + _qt_sbom_spdx_v2_external_document_ref "${external_document_ref}" + _qt_sbom_cydx_bom_serial_number_uuid "${bom_serial_number_uuid}" + _qt_sbom_spdx_repo_project_name_lowercase "${project_name}" + ) + + # The computation for these relies on the previous ones being set. + _qt_internal_sbom_compute_external_spdx_v2_id("${target}" external_spdx_v2_id) + _qt_internal_sbom_get_cydx_external_bom_link("${target}" external_bom_link) + + set_target_properties("${target}" PROPERTIES + _qt_sbom_spdx_v2_external_spdx_id "${external_spdx_v2_id}" + _qt_sbom_cydx_external_bom_link "${external_bom_link}" + ) +endfunction() + +# Returns the target name representing the current sbom project. +# When SBOM generation is disable, returns an empty string. +function(_qt_internal_sbom_get_current_project_target out_var) + if(NOT QT_GENERATE_SBOM) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + _qt_internal_sbom_get_root_project_name_lower_case(project_name) + + set(target "${project_name}ProjectSbom") + set(${out_var} "${target}" PARENT_SCOPE) +endfunction() + # Helper to add additional sbom information for an existing target. # Just appends the options to the target's sbom args property, which will will be evaluated # during finalization. +# For external sbom targets there is no finalization, so the relevant info is recorded +# immediately. function(_qt_internal_extend_sbom target) if(NOT QT_GENERATE_SBOM) return() @@ -1671,12 +1840,15 @@ function(_qt_internal_extend_sbom target) set(opt_args NO_FINALIZATION IMMEDIATE_FINALIZATION + IS_EXTERNAL_SBOM_ENTITY ) set(single_args TYPE # deprecated SBOM_ENTITY_TYPE DEFAULT_SBOM_ENTITY_TYPE FRIENDLY_PACKAGE_NAME + SPDX_ID + EXTERNAL_SBOM_DOCUMENT_TARGET ) set(multi_args "") cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -1692,29 +1864,69 @@ function(_qt_internal_extend_sbom target) _qt_internal_map_sbom_entity_type(sbom_entity_type ${ARGN}) - # Make sure a spdx id is recorded for the target right now, so it is "known" when handling - # relationships for other targets, even if the target was not yet finalized. - if(sbom_entity_type) - # Friendly package name is allowed to be empty. - set(package_name_option "") - if(arg_FRIENDLY_PACKAGE_NAME) - set(package_name_option PACKAGE_NAME "${arg_FRIENDLY_PACKAGE_NAME}") + # Make sure the spdx id and sbom entity type is recorded for the target right now, so it is + # "known" when handling relationships for other targets, even if the target was not yet + # finalized. + # The SBOM entity type is expected to be passed when creating a new SBOM target, or extending + # an existing target for the first time with SBOM info. + _qt_internal_sbom_get_spdx_id_for_target("${target}" spdx_id) + if(NOT spdx_id) + set(record_spdx_id_args "") + + # Isn't allowed to be empty when creating the spdx id. + if(sbom_entity_type) + list(APPEND record_spdx_id_args SBOM_ENTITY_TYPE "${sbom_entity_type}") + else() + message(FATAL_ERROR + "Target '${target}' is missing an SBOM_ENTITY_TYPE value. " + "Make sure to pass it when creating new SBOM target or extending an existing " + "target with SBOM infromation for the first time.") endif() - _qt_internal_sbom_record_target_spdx_id(${target} - SBOM_ENTITY_TYPE "${sbom_entity_type}" - ${package_name_option} - ) + # Friendly package name is allowed to be empty. + if(arg_FRIENDLY_PACKAGE_NAME) + list(APPEND record_spdx_id_args PACKAGE_NAME "${arg_FRIENDLY_PACKAGE_NAME}") + endif() + + # Allow specifying a custom spdx id, even for non-external targets. + if(arg_SPDX_ID) + list(APPEND record_spdx_id_args SPDX_ID "${arg_SPDX_ID}") + endif() + + if(arg_IS_EXTERNAL_SBOM_ENTITY) + list(APPEND record_spdx_id_args IS_EXTERNAL_SBOM_ENTITY) + endif() + + if(arg_EXTERNAL_SBOM_DOCUMENT_TARGET) + list(APPEND record_spdx_id_args + EXTERNAL_SBOM_DOCUMENT_TARGET ${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}) + endif() + + _qt_internal_sbom_record_target_spdx_id(${target} ${record_spdx_id_args}) endif() + get_target_property(is_system_library "${target}" _qt_internal_sbom_is_system_library) + get_target_property(is_project_sbom_target "${target}" _qt_sbom_is_project_sbom_target) set_property(TARGET ${target} APPEND PROPERTY _qt_finalize_sbom_args "${forward_args}") + # Record the target's relevant properties immediately after they are saved above, so we can + # refer to it in relationship entries. + if(arg_IS_EXTERNAL_SBOM_ENTITY AND QT_SBOM_GENERATE_CYDX_V1_6) + _qt_internal_sbom_record_external_target_dependecies(TARGETS "${target}") + endif() + # If requested via NO_FINALIZATION or the target is a system library, don't run finalization. # This is necessary for system libraries because those are handled in special code path just # before finishing project sbom generation, and finalizing them would cause issues because they # don't actually have a TYPE until a later point in time. - if(NOT arg_NO_FINALIZATION AND NOT is_system_library) + # Also skip regular processing / finalization for external targets, because their handling + # is different, and we don't create a regular package for them. + if(NOT arg_NO_FINALIZATION + AND NOT is_system_library + AND NOT is_project_sbom_target + AND NOT arg_IS_EXTERNAL_SBOM_ENTITY + ) # Defer finalization. In case it was already deferred, it will be a no-op. # Some targets need immediate finalization, like the PlatformInternal ones, # because otherwise they would be finalized after the sbom was already generated. @@ -1884,7 +2096,7 @@ function(_qt_internal_sbom_get_root_project_name_lower_case out_var) get_cmake_property(project_name _qt_internal_sbom_repo_project_name) if(NOT project_name) - message(FATAL_ERROR "No SBOM project name was set.") + message(FATAL_ERROR "The current active SBOM project name was not found.") endif() string(TOLOWER "${project_name}" repo_project_name_lowercase) @@ -1904,9 +2116,110 @@ function(_qt_internal_sbom_get_qt_repo_project_name_lower_case out_var) set(${out_var} "${repo_project_name_lowercase}" PARENT_SCOPE) endfunction() -# Get a spdx id to reference an external document. +# Compute a SPDX v2.3 DocumentRef ID, to reference the current project's SPDX document as an +# external document in another project. +# +# This is only meant to be used for exporting the value as part of the target's properties, to be +# used in a different project. +# +# It should NOT be used to refer to already exported targets. +# +# For querying the DocumentRef of an exported target, use +# _qt_internal_sbom_get_external_document_ref_spdx_id_from_sbom_target. +function(_qt_internal_sbom_compute_external_document_ref_spdx_id repo_name out_var) + _qt_internal_sbom_get_spdx_id_unique_suffix(spdx_id_unique_suffix) + set(${out_var} "DocumentRef-${repo_name}${spdx_id_unique_suffix}" PARENT_SCOPE) +endfunction() + +# Older deprecated function name of the function above, kept for compatibility in case it is used. function(_qt_internal_sbom_get_external_document_ref_spdx_id repo_name out_var) - set(${out_var} "DocumentRef-${repo_name}" PARENT_SCOPE) + if(NOT QT_NO_DEPRECATED_GET_EXTERNAL_DOCUMENT_REF_SPDX_ID) + message(DEPRECATION + "This function is deprecated. " + "Please use _qt_internal_sbom_compute_external_document_ref_spdx_id() instead." + "To silence this deprecation, pass " + "-DQT_NO_DEPRECATED_GET_EXTERNAL_DOCUMENT_REF_SPDX_ID=ON " + "when configuring the project." + ) + endif() + + _qt_internal_sbom_compute_external_document_ref_spdx_id("${repo_name}" external_document_ref) + + set(${out_var} "${external_document_ref}" PARENT_SCOPE) +endfunction() + +# Query the external reference DocumentRef ID from the given SBOM target. +# +# If CREATE_TEMPORARY_REF_WHEN_MISSING is set, it instead of erroring out when the document ref +# isn't found, create one and assign it to the to the usual target property. +# This allows referring to older targets that were exported without the necessary properties. +function(_qt_internal_sbom_get_external_document_ref_spdx_id_from_sbom_target) + if(NOT QT_GENERATE_SBOM) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + set(opt_args + CREATE_TEMPORARY_REF_WHEN_MISSING + ) + set(single_args + TARGET + OUT_VAR + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + if(NOT arg_TARGET) + message(FATAL_ERROR "TARGET argument is required.") + endif() + + if(NOT arg_OUT_VAR) + message(FATAL_ERROR "OUT_VAR argument is required.") + endif() + + set(target_unaliased "${arg_TARGET}") + _qt_internal_dealias_target(target_unaliased) + + get_target_property(external_document_ref + "${target_unaliased}" _qt_sbom_spdx_v2_external_document_ref) + + if(NOT external_document_ref) + if(NOT arg_CREATE_TEMPORARY_REF_WHEN_MISSING + AND NOT QT_SBOM_NO_AUTO_CREATE_DOCUMENT_REF_WHEN_MISSING) + message(FATAL_ERROR + "The target '${arg_TARGET}' does not have a recorded SPDX v2.3 external document " + "DocumentRef value recorded.") + else() + string(MAKE_C_IDENTIFIER "${arg_TARGET}" target_c_identifier) + string(REPLACE "_" "-" target_c_identifier "${target_c_identifier}") + _qt_internal_sbom_compute_external_document_ref_spdx_id("${target_c_identifier}" + external_document_ref + ) + set_target_properties("${target_unaliased}" PROPERTIES + _qt_sbom_spdx_v2_external_document_ref "${external_document_ref}") + + message(DEBUG "Did not find external document ref for target '${arg_TARGET}'. " + "Created one and set it to '${external_document_ref}' in the target's properties.") + endif() + endif() + + set(${arg_OUT_VAR} "${external_document_ref}" PARENT_SCOPE) +endfunction() + +# Computes a spdx id to reference the target's spdx v2 package via a SPDX v2 external document ref. +# To be used for exporting the value as part of the target's metadata. +function(_qt_internal_sbom_compute_external_spdx_v2_id target out_var) + get_target_property(project_name_lowercase "${target}" + _qt_sbom_spdx_repo_project_name_lowercase) + + _qt_internal_sbom_compute_external_document_ref_spdx_id( + "${project_name_lowercase}" external_document_ref) + + _qt_internal_sbom_get_spdx_id_for_target("${target}" spdx_id) + + set(ext_spdx_id "${external_document_ref}:${spdx_id}") + set(${out_var} "${ext_spdx_id}" PARENT_SCOPE) endfunction() # Sanitize a given value to be used as a SPDX id. @@ -1920,12 +2233,21 @@ function(_qt_internal_sbom_get_sanitized_spdx_id out_var hint) set(${out_var} "${spdx_id}" PARENT_SCOPE) endfunction() -# Generates a spdx id for a target and saves it its properties. +# Generates a spdx id for a target and saves it, the passed in SBOM_ENTITY_TYPE value, and a lot +# of other project specific properties like the spdx document namespace, cyclone dx document serial +# number, etc, in its target properties. +# A SBOM_ENTITY_TYPE value is required when saving the spdx id. + +# Exits early and returns the spdx id if it was already created earlier. function(_qt_internal_sbom_record_target_spdx_id target) - set(opt_args "") + set(opt_args + IS_EXTERNAL_SBOM_ENTITY + ) set(single_args + SPDX_ID PACKAGE_NAME SBOM_ENTITY_TYPE + EXTERNAL_SBOM_DOCUMENT_TARGET OUT_VAR ) set(multi_args "") @@ -1948,14 +2270,32 @@ function(_qt_internal_sbom_record_target_spdx_id target) set(package_name_for_spdx_id "${target}") endif() - _qt_internal_sbom_generate_target_package_spdx_id(package_spdx_id - SBOM_ENTITY_TYPE "${arg_SBOM_ENTITY_TYPE}" - PACKAGE_NAME "${package_name_for_spdx_id}" - ) + # If an explicit SPDX_ID is set, use it rather than generating one. + if(arg_SPDX_ID) + set(package_spdx_id "${arg_SPDX_ID}") + else() + _qt_internal_sbom_generate_target_package_spdx_id(package_spdx_id + SBOM_ENTITY_TYPE "${arg_SBOM_ENTITY_TYPE}" + PACKAGE_NAME "${package_name_for_spdx_id}" + ) + endif() + + set(save_spdx_id_args "") + + if(arg_IS_EXTERNAL_SBOM_ENTITY) + list(APPEND save_spdx_id_args IS_EXTERNAL_SBOM_ENTITY) + endif() + + if(arg_EXTERNAL_SBOM_DOCUMENT_TARGET) + list(APPEND save_spdx_id_args + EXTERNAL_SBOM_DOCUMENT_TARGET ${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}) + endif() + _qt_internal_sbom_save_spdx_id_for_target("${target}" SPDX_ID "${package_spdx_id}" PACKAGE_NAME "${package_name_for_spdx_id}" SBOM_ENTITY_TYPE "${arg_SBOM_ENTITY_TYPE}" + ${save_spdx_id_args} ) _qt_internal_sbom_is_qt_entity_type("${arg_SBOM_ENTITY_TYPE}" is_qt_entity_type) @@ -1987,9 +2327,13 @@ function(_qt_internal_sbom_generate_target_package_spdx_id out_var) _qt_internal_sbom_get_root_project_name_for_spdx_id(repo_project_name_spdx_id) _qt_internal_sbom_get_package_infix("${arg_SBOM_ENTITY_TYPE}" package_infix) + _qt_internal_sbom_get_spdx_id_unique_suffix(spdx_id_unique_suffix) - _qt_internal_sbom_get_sanitized_spdx_id(spdx_id - "SPDXRef-${repo_project_name_spdx_id}-${package_infix}-${arg_PACKAGE_NAME}") + string(CONCAT spdx_id_input + "SPDXRef-${repo_project_name_spdx_id}-${package_infix}-${arg_PACKAGE_NAME}" + "${spdx_id_unique_suffix}" + ) + _qt_internal_sbom_get_sanitized_spdx_id(spdx_id "${spdx_id_input}") set(${out_var} "${spdx_id}" PARENT_SCOPE) endfunction() @@ -2001,11 +2345,14 @@ endfunction() # Also saves the sbom entity type and package name, because it's needed when creating CycloneDX # components where the target is in an external document. function(_qt_internal_sbom_save_spdx_id_for_target target) - set(opt_args "") + set(opt_args + IS_EXTERNAL_SBOM_ENTITY + ) set(single_args SPDX_ID PACKAGE_NAME SBOM_ENTITY_TYPE + EXTERNAL_SBOM_DOCUMENT_TARGET ) set(multi_args "") cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -2023,6 +2370,32 @@ function(_qt_internal_sbom_save_spdx_id_for_target target) message(FATAL_ERROR "SBOM_ENTITY_TYPE must be set") endif() + if(arg_IS_EXTERNAL_SBOM_ENTITY AND NOT arg_EXTERNAL_SBOM_DOCUMENT_TARGET) + message(FATAL_ERROR + "Target '${target}' is marked as external with the IS_EXTERNAL_SBOM_ENTITY option " + "but no EXTERNAL_SBOM_DOCUMENT_TARGET was provided. Make sure to pass in a " + "an external sbom document target created by " + "_qt_internal_sbom_add_external_reference_document() to the mentioned option.") + endif() + + if(arg_EXTERNAL_SBOM_DOCUMENT_TARGET AND NOT TARGET "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}") + message(FATAL_ERROR + "The target '${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}' passed to " + "EXTERNAL_SBOM_DOCUMENT_TARGET does not exist.") + endif() + + if(arg_EXTERNAL_SBOM_DOCUMENT_TARGET) + get_target_property(is_external_project_sbom_target "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" + _qt_sbom_is_external_project_sbom_target) + if(NOT is_external_project_sbom_target) + message(FATAL_ERROR + "The target '${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}' passed to " + "EXTERNAL_SBOM_DOCUMENT_TARGET is not marked as an external project sbom target. " + "Make sure to create the target with " + "_qt_internal_sbom_add_external_reference_document().") + endif() + endif() + set(spdx_id "${arg_SPDX_ID}") message(DEBUG "Saving spdx id for target ${target}: ${spdx_id}") @@ -2033,18 +2406,50 @@ function(_qt_internal_sbom_save_spdx_id_for_target target) set_target_properties(${target_unaliased} PROPERTIES _qt_sbom_spdx_id "${spdx_id}") - # Retrieve repo specific properties. - get_property(repo_document_namespace - GLOBAL PROPERTY _qt_internal_sbom_repo_document_namespace) + # Retrieve some of the repo / project specific properties. + if(arg_IS_EXTERNAL_SBOM_ENTITY) + get_target_property(repo_document_namespace + "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" _qt_sbom_spdx_repo_document_namespace) + else() + get_property(repo_document_namespace + GLOBAL PROPERTY _qt_internal_sbom_repo_document_namespace) + endif() - get_property(bom_serial_number_uuid - GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid) + if(arg_IS_EXTERNAL_SBOM_ENTITY) + get_target_property(bom_serial_number_uuid + "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" _qt_sbom_cydx_bom_serial_number_uuid) + else() + get_property(bom_serial_number_uuid + GLOBAL PROPERTY _qt_internal_sbom_repo_cyclone_dx_bom_serial_number_uuid) + endif() - get_property(relative_installed_repo_document_path - GLOBAL PROPERTY _qt_internal_sbom_relative_installed_repo_document_path) + if(arg_IS_EXTERNAL_SBOM_ENTITY) + get_target_property(relative_installed_repo_document_path + "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" + _qt_sbom_spdx_relative_installed_repo_document_path) + else() + get_property(relative_installed_repo_document_path + GLOBAL PROPERTY _qt_internal_sbom_relative_installed_repo_document_path) + endif() - get_property(project_name_lowercase - GLOBAL PROPERTY _qt_internal_sbom_repo_project_name_lowercase) + if(NOT arg_IS_EXTERNAL_SBOM_ENTITY) + get_property(document_spdx_v2_tag_value_relative_path + GLOBAL PROPERTY _qt_internal_sbom_document_spdx_v2_tag_value_relative_path) + + get_property(document_spdx_v2_json_relative_path + GLOBAL PROPERTY _qt_internal_sbom_document_spdx_v2_json_relative_path) + + get_property(document_cydx_v1_6_json_relative_path + GLOBAL PROPERTY _qt_internal_sbom_document_cydx_v1_6_json_relative_path) + endif() + + if(arg_IS_EXTERNAL_SBOM_ENTITY) + get_target_property(project_name_lowercase + "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" _qt_sbom_spdx_repo_project_name_lowercase) + else() + get_property(project_name_lowercase + GLOBAL PROPERTY _qt_internal_sbom_repo_project_name_lowercase) + endif() # And save them on the target. set_property(TARGET ${target_unaliased} PROPERTY @@ -2055,6 +2460,20 @@ function(_qt_internal_sbom_save_spdx_id_for_target target) _qt_sbom_cydx_bom_serial_number_uuid "${bom_serial_number_uuid}") + if(NOT arg_IS_EXTERNAL_SBOM_ENTITY) + set_property(TARGET ${target_unaliased} PROPERTY + _qt_sbom_spdx_v2_document_tag_value_relative_path + "${document_spdx_v2_tag_value_relative_path}") + + set_property(TARGET ${target_unaliased} PROPERTY + _qt_sbom_spdx_v2_document_json_relative_path + "${document_spdx_v2_json_relative_path}") + + set_property(TARGET ${target_unaliased} PROPERTY + _qt_sbom_cydx_v1_6_document_json_relative_path + "${document_cydx_v1_6_json_relative_path}") + endif() + set_property(TARGET ${target_unaliased} PROPERTY _qt_sbom_spdx_relative_installed_repo_document_path "${relative_installed_repo_document_path}") @@ -2071,19 +2490,53 @@ function(_qt_internal_sbom_save_spdx_id_for_target target) _qt_sbom_entity_type "${arg_SBOM_ENTITY_TYPE}") - # Export the properties, so they can be queried by other repos. - # We also do it for versionless targets. - set(export_properties - _qt_sbom_entity_type - _qt_sbom_package_name - _qt_sbom_spdx_id - _qt_sbom_spdx_repo_document_namespace - _qt_sbom_cydx_bom_serial_number_uuid - _qt_sbom_spdx_relative_installed_repo_document_path - _qt_sbom_spdx_repo_project_name_lowercase - ) - set_property(TARGET "${target_unaliased}" APPEND PROPERTY - EXPORT_PROPERTIES "${export_properties}") + if(arg_IS_EXTERNAL_SBOM_ENTITY) + get_target_property(external_document_ref + "${arg_EXTERNAL_SBOM_DOCUMENT_TARGET}" _qt_sbom_spdx_v2_external_document_ref) + else() + _qt_internal_sbom_compute_external_document_ref_spdx_id( + "${project_name_lowercase}" external_document_ref) + endif() + + set_property(TARGET "${target_unaliased}" PROPERTY + _qt_sbom_spdx_v2_external_document_ref "${external_document_ref}") + + _qt_internal_sbom_compute_external_spdx_v2_id("${target_unaliased}" external_spdx_v2_id) + + set_property(TARGET "${target_unaliased}" PROPERTY + _qt_sbom_spdx_v2_external_spdx_id "${external_spdx_v2_id}") + + _qt_internal_sbom_get_cydx_external_bom_link("${target_unaliased}" external_bom_link) + set_property(TARGET "${target_unaliased}" PROPERTY + _qt_sbom_cydx_external_bom_link "${external_bom_link}") + + _qt_internal_sbom_get_cydx_external_urn_bom_version("${target_unaliased}" + external_urn_bom_version) + set_property(TARGET "${target_unaliased}" PROPERTY + _qt_sbom_cydx_external_urn_bom_version "${external_urn_bom_version}") + + if(NOT arg_IS_EXTERNAL_SBOM_ENTITY) + # Export the properties, so they can be queried by other repos. + # We also do it for versionless targets. + set(export_properties + _qt_sbom_entity_type + _qt_sbom_package_name + _qt_sbom_spdx_id + _qt_sbom_spdx_repo_document_namespace + _qt_sbom_spdx_v2_external_document_ref + _qt_sbom_spdx_v2_external_spdx_id + _qt_sbom_spdx_v2_document_tag_value_relative_path + _qt_sbom_spdx_v2_document_json_relative_path + _qt_sbom_cydx_bom_serial_number_uuid + _qt_sbom_cydx_external_bom_link + _qt_sbom_cydx_external_urn_bom_version + _qt_sbom_cydx_v1_6_document_json_relative_path + _qt_sbom_spdx_relative_installed_repo_document_path + _qt_sbom_spdx_repo_project_name_lowercase + ) + set_property(TARGET "${target_unaliased}" APPEND PROPERTY + EXPORT_PROPERTIES "${export_properties}") + endif() endfunction() # Returns whether the given sbom type is considered to be a Qt type like a module or a tool. @@ -2165,6 +2618,12 @@ function(_qt_internal_sbom_get_spdx_id_for_target target out_var) set(${out_var} "${spdx_id}" PARENT_SCOPE) endfunction() +# Retrieves a saved spdx id for the current project. Might be empty. +function(_qt_internal_sbom_get_current_project_spdx_id out_var) + get_cmake_property(spdx_id _qt_internal_sbom_project_spdx_id) + set(${out_var} "${spdx_id}" PARENT_SCOPE) +endfunction() + # Returns a package infix for a given target sbom type to be used in spdx package id generation. function(_qt_internal_sbom_get_package_infix type out_infix) if(type STREQUAL "QT_MODULE") @@ -2201,10 +2660,14 @@ function(_qt_internal_sbom_get_package_infix type out_infix) set(package_infix "3rdparty-library-with-files") elseif(type STREQUAL "THIRD_PARTY_SOURCES") set(package_infix "3rdparty-sources") + elseif(type STREQUAL "SBOM_PROJECT") + set(package_infix "sbom-project") elseif(type STREQUAL "TRANSLATIONS") set(package_infix "translations") elseif(type STREQUAL "RESOURCES") set(package_infix "resource") + elseif(type STREQUAL "BUILD_TOOL") + set(package_infix "build-tool") elseif(type STREQUAL "CUSTOM") set(package_infix "custom") elseif(type STREQUAL "CUSTOM_NO_INFIX") @@ -2252,10 +2715,14 @@ function(_qt_internal_sbom_get_package_purpose type out_purpose) set(package_purpose "LIBRARY") elseif(type STREQUAL "THIRD_PARTY_SOURCES") set(package_purpose "LIBRARY") + elseif(type STREQUAL "SBOM_PROJECT") + set(package_purpose "OTHER") elseif(type STREQUAL "TRANSLATIONS") set(package_purpose "OTHER") elseif(type STREQUAL "RESOURCES") set(package_purpose "OTHER") + elseif(type STREQUAL "BUILD_TOOL") + set(package_purpose "OTHER") elseif(type STREQUAL "CUSTOM") set(package_purpose "OTHER") elseif(type STREQUAL "CUSTOM_NO_INFIX") diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomOpsHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomOpsHelpers.cmake index 8208a33236..d52a527d39 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomOpsHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomOpsHelpers.cmake @@ -166,7 +166,7 @@ endfunction() # DEPS_FOUND_FOR_$OP_KEY var. function(_qt_internal_sbom_verify_if_sbom_op_dependencies_are_found) set(opt_args - REQUIRED + FINAL_ATTEMPT PYTHON_FOUND DEP_FOUND EVERYTHING_FOUND @@ -176,17 +176,20 @@ function(_qt_internal_sbom_verify_if_sbom_op_dependencies_are_found) PYTHON_PATH PYTHON_VERSION DEP_PACKAGE_NAME + PYTHON_FIND_OUTPUT DEP_FIND_OUTPUT + ATTEMPT_MESSAGE + ATTEMPT_RESULT_MESSAGE OP_KEY + ATTEMPT_LOG_OUT_VAR + ATTEMPT_COUNT_OUT_VAR ) - set(multi_args - PYTHON_COMMON_ARGS - ) + set(multi_args "") cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") if(arg_EVERYTHING_FOUND) - message(DEBUG "Python Dependencies found. " - "Using Python '${arg_PYTHON_PATH}' for running SBOM op '${arg_OP_KEY}'.") + message(DEBUG "Python and dependencies found for SBOM operation '${arg_OP_KEY}'. " + "Using Python '${arg_PYTHON_PATH}'") if(NOT QT_INTERNAL_SBOM_PYTHON_EXECUTABLE) message(DEBUG "Setting QT_INTERNAL_SBOM_PYTHON_EXECUTABLE to ${arg_PYTHON_PATH}") @@ -202,40 +205,110 @@ function(_qt_internal_sbom_verify_if_sbom_op_dependencies_are_found) return() endif() - if(arg_REQUIRED) - set(message_type "FATAL_ERROR") - else() - set(message_type "DEBUG") - endif() - if(NOT arg_PYTHON_FOUND) - # Look for python one more time, this time without QUIET, to show an error why it - # wasn't found. - if(arg_REQUIRED) - _qt_internal_sbom_find_python_helper(${arg_PYTHON_COMMON_ARGS} - OUT_VAR_PYTHON_PATH unused_python - OUT_VAR_PYTHON_FOUND unused_found - ) - endif() - message(${message_type} - "Python ${arg_REQUIRED_VERSION} for running SBOM op '${arg_OP_KEY}' NOT found.") + string(CONCAT not_found_message + "Python ${arg_REQUIRED_VERSION} for running SBOM operation '${arg_OP_KEY}' NOT found.\n" + "Suggestion: In case if Python is installed, but not in a standard location, specify " + "it using -DQT_SBOM_PYTHON_INTERP=\n" + ) elseif(NOT arg_DEP_FOUND) - - set(extra_install_message "") - if(message_type STREQUAL "FATAL_ERROR") - set(extra_install_message - "Install it using pip install '${arg_DEP_PACKAGE_NAME}' \n") - endif() - message(${message_type} - "Python dependency for running SBOM op '${arg_OP_KEY}' NOT found:\n" - ${extra_install_message} - "Details:\n" - "Python interpreter: ${arg_PYTHON_PATH}\n" - "Error output: \n${arg_DEP_FIND_OUTPUT}\n\n" + string(CONCAT not_found_message + "Python dependency for running SBOM operation '${arg_OP_KEY}' NOT found.\n" + "Suggestion: Install it using pip install '${arg_DEP_PACKAGE_NAME}'\n" ) endif() + + set(dep_find_contents "") + if(arg_DEP_FIND_OUTPUT) + string(CONCAT dep_find_contents + "Dependency find log begins.\n${arg_DEP_FIND_OUTPUT}\n" + "Dependency find log ends.\n" + ) + endif() + + string(CONCAT current_attempt_message + "${arg_ATTEMPT_MESSAGE}\n" + "Result: ${not_found_message}\n" + "Python find log begins.\n${arg_PYTHON_FIND_OUTPUT}\n" + "Python find log ends.\n" + "${dep_find_contents}" + "${arg_ATTEMPT_RESULT_MESSAGE}\n\n" + ) + + message(DEBUG "${current_attempt_message}") + + if(arg_FINAL_ATTEMPT) + set(previous_attempts_contents "") + if(${arg_ATTEMPT_LOG_OUT_VAR}) + string(CONCAT previous_attempts_contents + "Previous attempts log below.\n" + "${${arg_ATTEMPT_LOG_OUT_VAR}}" + ) + endif() + string(CONCAT final_attempt_message + "${current_attempt_message}\n" + "${previous_attempts_contents}" + ) + message(FATAL_ERROR "${final_attempt_message}") + endif() + + # Collect all previous attempt messages, to show them at the very end if not found. + if(arg_ATTEMPT_LOG_OUT_VAR) + set(attempt_count "${${arg_ATTEMPT_COUNT_OUT_VAR}}") + math(EXPR attempt_count "${attempt_count} + 1") + set(${arg_ATTEMPT_COUNT_OUT_VAR} "${attempt_count}" PARENT_SCOPE) + + string(CONCAT attempt_log_content + "${${arg_ATTEMPT_LOG_OUT_VAR}}\n" + "Attempt ${attempt_count}:\n" + "${current_attempt_message}") + set(${arg_ATTEMPT_LOG_OUT_VAR} "${attempt_log_content}" PARENT_SCOPE) + endif() endfunction() +# Helper macro to output a debug or error message when python or one of its dependencies are not +# found. Expects the caller to set all of the vars. +# Meant to reduce the line noise due to the repeated calls. +macro(_qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda) + # Assemble args to show what wasn't found. + if(python_found) + list(APPEND verify_args PYTHON_FOUND) + endif() + if(dep_found) + list(APPEND verify_args DEP_FOUND) + endif() + if(everything_found) + list(APPEND verify_args EVERYTHING_FOUND) + endif() + if(python_path) + list(APPEND verify_args PYTHON_PATH "${python_path}") + endif() + if(python_version) + list(APPEND verify_args PYTHON_VERSION "${python_version}") + endif() + if(python_find_output) + list(APPEND verify_args PYTHON_FIND_OUTPUT "${python_find_output}") + endif() + if(dep_find_output) + list(APPEND verify_args DEP_FIND_OUTPUT "${dep_find_output}") + endif() + if(attempt_message) + list(APPEND verify_args ATTEMPT_MESSAGE "${attempt_message}") + endif() + if(attempt_result_message) + list(APPEND verify_args ATTEMPT_RESULT_MESSAGE "${attempt_result_message}") + endif() + + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found( + ${verify_args} + REQUIRED_VERSION "${required_version}" + OP_KEY "${arg_OP_KEY}" + DEP_PACKAGE_NAME "${dep_package_name}" + ATTEMPT_LOG_OUT_VAR attempt_log + ATTEMPT_COUNT_OUT_VAR attempt_count + ) +endmacro() + # Helper to find a python interpreter and a specific python dependency, e.g. to be able to generate # a SPDX JSON SBOM, or run post-installation steps like NTIA verification. # The exact dependency should be specified as the OP_KEY. @@ -244,6 +317,8 @@ endfunction() # avoid conflicts with any other found python interpreter. # Also caches the python version found in QT_INTERNAL_SBOM_PYTHON_VERSION, so we can show it # in the configure summary. +# Attempts to find a suitable Python interpreter with multiple searching approaches, due to platform +# specifics and quirks in how the FindPython module behaves. function(_qt_internal_sbom_find_and_handle_sbom_op_dependencies) set(opt_args REQUIRED @@ -298,86 +373,151 @@ function(_qt_internal_sbom_find_and_handle_sbom_op_dependencies) set(everything_found FALSE) - # On macOS FindPython prefers looking in the system framework location, but that usually would + # Used by the macro calls below below to collect debug find output across attempts. + set(attempt_log "") + set(attempt_count 0) + + # Look in QT_SBOM_PYTHON_INTERP if it's set. + # If QT_SBOM_FORCE_USE_PYTHON_INTERP is set, attempt to use it without preforming a search. + _qt_internal_sbom_get_sbom_python_interp_path( + OUT_VAR_FOUND sbom_python_interp_found + OUT_VAR_PYTHON_PATH sbom_python_interp_path + OUT_VAR_PYTHON_DIR_PATH sbom_python_interp_dir + ) + if(sbom_python_interp_found) + set(extra_python_args + QUIET + ) + # It's possible that sbom_python_interp_path can't be computed, so we need to check that + # it's not empty. + if(QT_SBOM_FORCE_USE_PYTHON_INTERP AND sbom_python_interp_path) + set(using_message "${sbom_python_interp_path}") + list(APPEND extra_python_args + FORCE_SET_INTERPRETER_PATH + INTERPRETER_PATH "${sbom_python_interp_path}" + ) + else() + set(using_message "${sbom_python_interp_dir}") + list(APPEND extra_python_args + SEARCH_IN_INTERPRETER_DIR_PATH + INTERPRETER_DIR_PATH "${sbom_python_interp_dir}" + ) + endif() + string(CONCAT attempt_message + "Looking for Python and dependencies for operation '${arg_OP_KEY}'. " + "Searching using QT_SBOM_PYTHON_INTERP: '${using_message}'.") + _qt_internal_sbom_find_python_and_dependency_helper_lambda() + + set(attempt_result_message "") + if(NOT everything_found) + string(CONCAT attempt_result_message + "SBOM Python search using QT_SBOM_PYTHON_INTERP did " + "not find all dependencies for operation '${arg_OP_KEY}'. Search continues." + ) + endif() + + set(verify_args "") + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda() + endif() + + # Look into any custom provided root dir, that was not set via QT_SBOM_PYTHON_INTERP. + _qt_internal_sbom_get_python_root_dir(OUT_VAR_PYTHON_ROOT_DIR_PATH python_root_dir) + if(NOT everything_found AND python_root_dir) + set(extra_python_args + QUIET + SEARCH_IN_ROOT_DIR + ) + string(CONCAT attempt_message + "Looking for Python and dependencies for operation '${arg_OP_KEY}'. " + "Searching using Python3_ROOT_DIR: '${python_root_dir}'.") + _qt_internal_sbom_find_python_and_dependency_helper_lambda() + + set(attempt_result_message "") + if(NOT everything_found) + string(CONCAT attempt_result_message + "SBOM Python search using Python3_ROOT_DIR did not find all dependencies " + "for operation '${arg_OP_KEY}'. Search continues." + ) + endif() + + set(verify_args "") + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda() + endif() + + # On macOS, FindPython prefers looking in the system framework location, but that usually would # not have the required dependencies. So we first look in it, and then fallback to any other # non-framework python found. - if(CMAKE_HOST_APPLE) - set(extra_python_args SEARCH_IN_FRAMEWORKS QUIET) - message(DEBUG "Looking for Python and dependencies for op '${arg_OP_KEY}' " - "in the system framework location first.") + if(NOT everything_found AND CMAKE_HOST_APPLE) + set(extra_python_args + QUIET + SEARCH_IN_FRAMEWORKS + ) + string(CONCAT attempt_message + "Looking for Python and dependencies for operation '${arg_OP_KEY}'. " + "Searching in the macOS framework locations.") _qt_internal_sbom_find_python_and_dependency_helper_lambda() + + set(attempt_result_message "") if(NOT everything_found) - # Assemble args to show what wasn't found. - set(verify_args "") - if(python_found) - list(APPEND verify_args PYTHON_FOUND) - endif() - if(dep_found) - list(APPEND verify_args DEP_FOUND) - endif() - if(everything_found) - list(APPEND verify_args EVERYTHING_FOUND) - endif() - if(python_path) - list(APPEND verify_args PYTHON_PATH "${python_path}") - endif() - if(python_version) - list(APPEND verify_args PYTHON_VERSION "${python_version}") - endif() - if(dep_find_output) - list(APPEND verify_args DEP_FIND_OUTPUT "${dep_find_output}") - endif() - - _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found( - ${verify_args} - REQUIRED_VERSION "${required_version}" - OP_KEY "${arg_OP_KEY}" - DEP_PACKAGE_NAME "${dep_package_name}" - PYTHON_COMMON_ARGS ${python_common_args} + string(CONCAT attempt_result_message + "macOS-specific SBOM Python search did not find all dependencies " + "for operation '${arg_OP_KEY}'. Search continues." ) - - message(DEBUG "Initial Apple-specific SBOM Python search did not find all dependencies " - "for op ${arg_OP_KEY}, looking again outside of the system framework location.") endif() + + set(verify_args "") + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda() endif() - # Looking again if something wasn't found, or a search was not done yet. - if(NOT everything_found) - set(extra_python_args QUIET) - message(DEBUG "Looking for Python and dependencies for op '${arg_OP_KEY}'.") + # On Windows, also look in the registry first. + if(NOT everything_found AND CMAKE_HOST_WIN32) + set(extra_python_args + QUIET + SEARCH_IN_REGISTRY + ) + string(CONCAT attempt_message + "Looking for Python and dependencies for operation '${arg_OP_KEY}'. Searching in the " + " Windows registry.") _qt_internal_sbom_find_python_and_dependency_helper_lambda() + + set(attempt_result_message "") + if(NOT everything_found) + string(CONCAT attempt_result_message + "Windows-specific SBOM Python search did not find all dependencies " + "for operation '${arg_OP_KEY}'. Search continues." + ) + endif() + + set(verify_args "") + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda() endif() - # Assemble args to show what was or wasn't found. - set(verify_args "") - if(arg_REQUIRED) - list(APPEND verify_args REQUIRED) + # Do a final lookup without all the approaches above. + if(NOT everything_found) + set(extra_python_args + QUIET + ) + string(CONCAT attempt_message + "Looking for Python and dependencies for operation " + "'${arg_OP_KEY}'. Searching default locations as per FindPython3 docs.") + _qt_internal_sbom_find_python_and_dependency_helper_lambda() + + set(attempt_result_message "") + if(NOT everything_found) + string(CONCAT attempt_result_message + "SBOM Python search in default locations did not find all dependencies " + "for operation '${arg_OP_KEY}'. Search concluded." + ) + endif() + + set(verify_args "") + # If REQUIRED was passed, and we are at the final attempt, in case we didn't find the + # deps, we will error out. + if(arg_REQUIRED) + list(APPEND verify_args FINAL_ATTEMPT) + endif() + _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found_lambda() endif() - if(python_found) - list(APPEND verify_args PYTHON_FOUND) - endif() - if(dep_found) - list(APPEND verify_args DEP_FOUND) - endif() - if(everything_found) - list(APPEND verify_args EVERYTHING_FOUND) - endif() - if(python_path) - list(APPEND verify_args PYTHON_PATH "${python_path}") - endif() - if(python_version) - list(APPEND verify_args PYTHON_VERSION "${python_version}") - endif() - if(dep_find_output) - list(APPEND verify_args DEP_FIND_OUTPUT "${dep_find_output}") - endif() - _qt_internal_sbom_verify_if_sbom_op_dependencies_are_found( - ${verify_args} - REQUIRED_VERSION "${required_version}" - OP_KEY "${arg_OP_KEY}" - DEP_PACKAGE_NAME "${dep_package_name}" - PYTHON_COMMON_ARGS ${python_common_args} - ) if(arg_OUT_VAR_DEPS_FOUND) set(${arg_OUT_VAR_DEPS_FOUND} "${QT_INTERNAL_SBOM_DEPS_FOUND_FOR_${arg_OP_KEY}}" diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomPythonHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomPythonHelpers.cmake index 6bff48edeb..28af47439c 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomPythonHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomPythonHelpers.cmake @@ -15,6 +15,7 @@ macro(_qt_internal_sbom_find_python_and_dependency_helper_lambda) OUT_VAR_PYTHON_VERSION python_version OUT_VAR_DEP_FOUND dep_found OUT_VAR_PYTHON_AND_DEP_FOUND everything_found + OUT_VAR_PYTHON_FIND_OUTPUT python_find_output OUT_VAR_DEP_FIND_OUTPUT dep_find_output ) endmacro() @@ -31,6 +32,7 @@ function(_qt_internal_sbom_find_python_and_dependency_helper) OUT_VAR_PYTHON_VERSION OUT_VAR_DEP_FOUND OUT_VAR_PYTHON_AND_DEP_FOUND + OUT_VAR_PYTHON_FIND_OUTPUT OUT_VAR_DEP_FIND_OUTPUT ) set(multi_args @@ -68,6 +70,7 @@ function(_qt_internal_sbom_find_python_and_dependency_helper) OUT_VAR_PYTHON_PATH python_path_inner OUT_VAR_PYTHON_FOUND python_found_inner OUT_VAR_PYTHON_VERSION python_version_inner + OUT_VAR_PYTHON_FIND_OUTPUT python_find_output_inner ) if(python_found_inner AND python_path_inner) @@ -90,14 +93,14 @@ function(_qt_internal_sbom_find_python_and_dependency_helper) endif() set(${arg_OUT_VAR_DEP_FOUND} "${dep_found_inner}" PARENT_SCOPE) set(${arg_OUT_VAR_PYTHON_AND_DEP_FOUND} "${everything_found_inner}" PARENT_SCOPE) + set(${arg_OUT_VAR_PYTHON_FIND_OUTPUT} "${python_find_output_inner}" PARENT_SCOPE) set(${arg_OUT_VAR_DEP_FIND_OUTPUT} "${dep_find_output_inner}" PARENT_SCOPE) endfunction() -# Tries to find the python intrepreter, given the QT_SBOM_PYTHON_INTERP path hint, as well as -# other options. +# Tries to find a python intrepreter for SBOM handling. # Ignores any previously found python. # Returns the python interpreter path and whether it was successfully found, along with the version -# found. +# found and some debug output when not found. # # This is intentionally a function, and not a macro, to prevent overriding the Python3_EXECUTABLE # non-cache variable in a global scope in case if a different python is found and used for a @@ -110,13 +113,20 @@ endfunction() function(_qt_internal_sbom_find_python_helper) set(opt_args SEARCH_IN_FRAMEWORKS + SEARCH_IN_REGISTRY + SEARCH_IN_ROOT_DIR + SEARCH_IN_INTERPRETER_DIR_PATH + FORCE_SET_INTERPRETER_PATH QUIET ) set(single_args VERSION + INTERPRETER_PATH + INTERPRETER_DIR_PATH OUT_VAR_PYTHON_PATH OUT_VAR_PYTHON_FOUND OUT_VAR_PYTHON_VERSION + OUT_VAR_PYTHON_FIND_OUTPUT ) set(multi_args "") cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") @@ -130,9 +140,59 @@ function(_qt_internal_sbom_find_python_helper) message(FATAL_ERROR "OUT_VAR_PYTHON_FOUND var is required") endif() + set(find_output "Search options:") + # Allow disabling looking for a python interpreter shipped as part of a macOS system framework. if(NOT arg_SEARCH_IN_FRAMEWORKS) set(Python3_FIND_FRAMEWORK NEVER) + list(APPEND find_output "Will NOT search in macOS framework locations.") + else() + list(APPEND find_output "Will search in macOS framework locations.") + endif() + + if(NOT arg_SEARCH_IN_REGISTRY) + set(Python3_FIND_REGISTRY NEVER) + list(APPEND find_output "Will NOT search in Windows registry.") + else() + list(APPEND find_output "Will search in Windows registry.") + endif() + + # Remove the root dir if not requested to search in it. + if(NOT arg_SEARCH_IN_ROOT_DIR) + unset(Python3_ROOT_DIR) + + # Temporarily also unset the env var. + set(python_root_dir_env_value "$ENV{Python3_ROOT_DIR}") + if(python_root_dir_env_value AND NOT QT_SBOM_NO_PYTHON_ROOT_DIR_ENV_BACKUP) + set(python_root_dir_env_backup "$ENV{Python3_ROOT_DIR}") + unset(ENV{Python3_ROOT_DIR}) + endif() + + list(APPEND find_output "Will NOT search in Python3_ROOT_DIR.") + else() + _qt_internal_sbom_get_python_root_dir(OUT_VAR_PYTHON_ROOT_DIR_PATH Python3_ROOT_DIR) + list(APPEND find_output "Will search in Python3_ROOT_DIR: '${Python3_ROOT_DIR}'.") + endif() + + set(force_python_interpreter_path "") + if(arg_FORCE_SET_INTERPRETER_PATH AND arg_INTERPRETER_PATH) + set(force_python_interpreter_path "${arg_INTERPRETER_PATH}") + + list(APPEND find_output + "Will force set Python3_EXECUTABLE to provided INTERPRETER_PATH: " + "'${arg_INTERPRETER_PATH}'.") + else() + list(APPEND find_output "Will NOT force set Python3_EXECUTABLE to INTERPRETER_PATH.") + endif() + + if(arg_SEARCH_IN_INTERPRETER_DIR_PATH AND arg_INTERPRETER_DIR_PATH) + # Python3_ROOT_DIR expects a directory, not a path. + set(Python3_ROOT_DIR "${arg_INTERPRETER_DIR_PATH}") + + list(APPEND find_output + "Will search in provided INTERPRETER_DIR_PATH: '${arg_INTERPRETER_DIR_PATH}'.") + else() + list(APPEND find_output "Will NOT search in INTERPRETER_DIR_PATH.") endif() set(required_version "") @@ -141,32 +201,158 @@ function(_qt_internal_sbom_find_python_helper) endif() set(find_quiet "") - if(arg_QUIET) + if(arg_QUIET AND NOT QT_INTERNAL_SBOM_NO_FIND_PYTHON_QUIET) set(find_quiet "QUIET") endif() - # Locally reset any executable that was possibly already found. - # We do this to ensure we always re-do the lookup/ - # This needs to be set to an empty string, to override any cache variable - set(Python3_EXECUTABLE "") + # When performing a search, locally reset any executable that was possibly already found. + # We do this to ensure we always re-do the lookup. + # This needs to be set to an empty string, to override any cache variable. + # When FORCE_SET_INTERPRETER_PATH is used, set the executable to the given path. + if(arg_FORCE_SET_INTERPRETER_PATH + AND force_python_interpreter_path + AND EXISTS "${force_python_interpreter_path}" + ) + set(Python3_EXECUTABLE "${force_python_interpreter_path}") + else() + set(Python3_EXECUTABLE "") + endif() # This needs to be unset, because the Python module checks whether the variable is defined, not # whether it is empty. unset(_Python3_EXECUTABLE) - if(QT_SBOM_PYTHON_INTERP) - set(Python3_ROOT_DIR ${QT_SBOM_PYTHON_INTERP}) + find_package(Python3 ${required_version} ${find_quiet} COMPONENTS Interpreter) + + if(python_root_dir_env_backup AND NOT QT_SBOM_NO_PYTHON_ROOT_DIR_ENV_BACKUP) + set(ENV{Python3_ROOT_DIR} "${python_root_dir_env_backup}") endif() - find_package(Python3 ${required_version} ${find_quiet} COMPONENTS Interpreter) + if(Python3_Interpreter_FOUND) + list(APPEND find_output + "Python interpreter found: '${Python3_EXECUTABLE} (version ${Python3_VERSION})'.") + else() + list(APPEND find_output "Python interpreter NOT found.") + endif() + + list(JOIN find_output "\n" find_output_joined) set(${arg_OUT_VAR_PYTHON_PATH} "${Python3_EXECUTABLE}" PARENT_SCOPE) set(${arg_OUT_VAR_PYTHON_FOUND} "${Python3_Interpreter_FOUND}" PARENT_SCOPE) + set(${arg_OUT_VAR_PYTHON_FIND_OUTPUT} "${find_output_joined}" PARENT_SCOPE) if(arg_OUT_VAR_PYTHON_VERSION) set(${arg_OUT_VAR_PYTHON_VERSION} "${Python3_VERSION}" PARENT_SCOPE) endif() endfunction() +# Helper to retrieve the python interpreter path and directory, from either a QT_SBOM_PYTHON_INTERP +# env var or regular (cache) var, when one of them is set. +# The regular var is preferred. +# In the very first implementation, the var expected to be passed an interpreter path, rather +# than the dir where the python interpreter is located, which is what FindPython's +# Python3_ROOT_DIR expects. +# Now both cases are handled properly. So the variable name is a bit of a misnomer, but we keep +# it for compatibility. +function(_qt_internal_sbom_get_sbom_python_interp_path) + set(opt_args "") + set(single_args + OUT_VAR_FOUND + OUT_VAR_PYTHON_PATH + OUT_VAR_PYTHON_DIR_PATH + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(candidates + "${QT_SBOM_PYTHON_INTERP}" + "$ENV{QT_SBOM_PYTHON_INTERP}" + ) + + set(something_found FALSE) + foreach(candidate IN LISTS candidates) + if(NOT candidate OR NOT EXISTS "${candidate}") + continue() + endif() + + set(something_found TRUE) + if(IS_DIRECTORY "${candidate}") + set(interp_dir "${candidate}") + set(interp_path "") + + # We need to find the executable in the given directory, to be able to assign it to + # Python3_EXECUTABLE when FORCE_SET_INTERPRETER_PATH is used. + find_program(QT_INTERNAL_SBOM_PYTHON_INTERP_PATH + NAMES python3 python + HINTS "${interp_dir}" + NO_DEFAULT_PATH + ) + if(QT_INTERNAL_SBOM_PYTHON_INTERP_PATH) + set(interp_path "${QT_INTERNAL_SBOM_PYTHON_INTERP_PATH}") + message(DEBUG + "Found python executable '${interp_path}' in QT_SBOM_PYTHON_INTERP candidate " + "directory: '${candidate}'.") + else() + message(DEBUG + "QT_SBOM_PYTHON_INTERP '${candidate}' is a directory, but no " + "python executable found in it.") + endif() + else() + get_filename_component(interp_dir "${candidate}" DIRECTORY) + set(interp_path "${candidate}") + endif() + break() + endforeach() + + if(arg_OUT_VAR_FOUND) + set(${arg_OUT_VAR_FOUND} "${something_found}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_PYTHON_PATH) + set(${arg_OUT_VAR_PYTHON_PATH} "${interp_path}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_PYTHON_DIR_PATH) + set(${arg_OUT_VAR_PYTHON_DIR_PATH} "${interp_dir}" PARENT_SCOPE) + endif() +endfunction() + +# Returns the value of Python3_ROOT_DIR if it's set, either as a cmake variable or env var. +function(_qt_internal_sbom_get_python_root_dir) + set(opt_args "") + set(single_args + OUT_VAR_FOUND + OUT_VAR_PYTHON_ROOT_DIR_PATH + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + _qt_internal_validate_all_args_are_parsed(arg) + + set(candidates + "${Python3_ROOT_DIR}" + "$ENV{Python3_ROOT_DIR}" + ) + + set(python_root_dir "") + + set(something_found FALSE) + foreach(candidate IN LISTS candidates) + if(NOT candidate OR NOT EXISTS "${candidate}") + continue() + endif() + + set(something_found TRUE) + if(IS_DIRECTORY "${candidate}") + set(python_root_dir "${candidate}") + endif() + endforeach() + + if(arg_OUT_VAR_FOUND) + set(${arg_OUT_VAR_FOUND} "${something_found}" PARENT_SCOPE) + endif() + if(arg_OUT_VAR_PYTHON_ROOT_DIR_PATH) + set(${arg_OUT_VAR_PYTHON_ROOT_DIR_PATH} "${python_root_dir}" PARENT_SCOPE) + endif() +endfunction() + # Helper that takes an python import statement to run using the given python interpreter path, # to confirm that the given python dependency can be found. # Returns whether the dependency was found and the output of running the import, for error handling. @@ -205,11 +391,14 @@ function(_qt_internal_sbom_find_python_dependency_helper) if("${res}" STREQUAL "0") set(found TRUE) - set(output "${output}") + string(CONCAT output + "SBOM Python dependency '${arg_DEPENDENCY_IMPORT_STATEMENT}' found. " + "Output:\n${output}") else() set(found FALSE) - string(CONCAT output "SBOM Python dependency ${arg_DEPENDENCY_IMPORT_STATEMENT} NOT found. " - "Error:\n${output}") + string(CONCAT output + "SBOM Python dependency '${arg_DEPENDENCY_IMPORT_STATEMENT}' NOT found. " + "Output:\n${output} Exit code: ${res}") endif() set(${arg_OUT_VAR_FOUND} "${found}" PARENT_SCOPE) @@ -240,13 +429,26 @@ function(_qt_internal_sbom_find_python_dependency_program) # The path to python installed apps is different on Windows compared to UNIX, so we use # a different path than where the python interpreter might be located. if(QT_SBOM_PYTHON_APPS_PATH) - list(APPEND hints ${QT_SBOM_PYTHON_APPS_PATH}) + list(APPEND hints "${QT_SBOM_PYTHON_APPS_PATH}") endif() # Sometimes the installed apps might be in the same location as the interepreter, if both are # in a virtual env. So look also in the interpreter path. - if(QT_SBOM_PYTHON_INTERP) - list(APPEND hints ${QT_SBOM_PYTHON_INTERP}) + _qt_internal_sbom_get_sbom_python_interp_path(OUT_VAR_PYTHON_DIR_PATH sbom_python_interp_dir) + if(sbom_python_interp_dir) + list(APPEND hints "${sbom_python_interp_dir}") + endif() + + # If we already found a python interpreter for sbom purposes, look in its parent directory. + if(QT_INTERNAL_SBOM_PYTHON_EXECUTABLE) + get_filename_component(python_interp_dir "${QT_INTERNAL_SBOM_PYTHON_EXECUTABLE}" DIRECTORY) + list(APPEND hints "${python_interp_dir}") + endif() + + # Look in the python root dir as well. + _qt_internal_sbom_get_python_root_dir(OUT_VAR_PYTHON_ROOT_DIR_PATH python_root_dir) + if(python_root_dir) + list(APPEND hints "${python_root_dir}") endif() find_program(${cache_var} diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomQtEntityHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomQtEntityHelpers.cmake index 1ccc64421b..bd4de23c80 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicSbomQtEntityHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicSbomQtEntityHelpers.cmake @@ -288,6 +288,13 @@ function(_qt_internal_sbom_get_qt_entity_repo_source_dir target) message(FATAL_ERROR "OUT_VAR must be set") endif() + # Interface libs don't have a source dir. Return early, to avoid errors with CMake 3.16. + get_target_property(target_type "${target}" TYPE) + if(target_type STREQUAL "INTERFACE_LIBRARY") + set(${arg_OUT_VAR} "" PARENT_SCOPE) + return() + endif() + get_target_property(repo_source_dir "${target}" SOURCE_DIR) # Get the path relative to the PROJECT_SOURCE_DIR diff --git a/local/recipes/qt/qtbase/source/cmake/QtPublicWindowsHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtPublicWindowsHelpers.cmake index a824917b67..7a3e5e6ff2 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtPublicWindowsHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtPublicWindowsHelpers.cmake @@ -1,6 +1,134 @@ # Copyright (C) 2024 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause +function(_qt_internal_normalize_project_version) + # Default if PROJECT_VERSION is missing or empty + if(NOT DEFINED PROJECT_VERSION OR PROJECT_VERSION STREQUAL "") + set(_version "1.0.0.0") + else() + set(_version "${PROJECT_VERSION}") + endif() + + # Split version into components + string(REPLACE "." ";" _ver_list "${_version}") + + # Ensure exactly 4 segments + list(LENGTH _ver_list _len) + while(_len LESS 4) + list(APPEND _ver_list "0") + list(LENGTH _ver_list _len) + endwhile() + + # Truncate extra segments + list(SUBLIST _ver_list 0 4 _ver_list) + + # Windows Application Manifests require a 4-part version (Major.Minor.Build.Revision). + # Each segment is stored as a 16-bit unsigned integer (USHORT). + # Values exceeding 65535 will cause schema validation errors in MSIX/AppX + # or 'Side-by-Side' (SxS) configuration failures in Win32 executables. + # We clamp the values here to ensure the manifest remains valid for Windows. + set(_ver_list_tmp "") + foreach(i RANGE 0 3) + list(GET _ver_list ${i} seg) + if(seg LESS 0) + message(WARNING + "Version segment '${seg}' is less than 0. Capping to 0.") + set(seg 0) + elseif(seg GREATER 65535) + message(WARNING + "Version segment '${seg}' exceeds 65535. Capping to 65535.") + set(seg 65535) + endif() + list(APPEND _ver_list_tmp ${seg}) + endforeach() + + list(GET _ver_list_tmp 0 _maj) + list(GET _ver_list_tmp 1 _min) + list(GET _ver_list_tmp 2 _build) + list(GET _ver_list_tmp 3 _revision) + + # Recompose canonical version + set(PROJECT_VERSION + "${_maj}.${_min}.${_build}.${_revision}" + PARENT_SCOPE) +endfunction() + +function(_qt_internal_finalize_windows_app target) + get_target_property(targetType "${target}" TYPE) + if(NOT "${targetType}" STREQUAL "EXECUTABLE" AND + NOT "${targetType}" STREQUAL "SHARED_LIBRARY") + return() + endif() + + # If the project already specifies a custom file, we don't override it. + get_target_property(sources "${target}" SOURCES) + set(manifest_in "${sources}") + list(FILTER manifest_in INCLUDE REGEX ".*\.manifest") + if(manifest_in) + message(DEBUG "Skipping manifest magic due to user specified manifest file") + return() + endif() + + set(manifest_in "${__qt_internal_cmake_windows_support_files_path}/app.exe.manifest.in") + + get_target_property(output_name ${target} OUTPUT_NAME) + if(NOT output_name) + set(output_name "${target}") + endif() + string(MAKE_C_IDENTIFIER "${target}" target_identifier) + set(manifest_out_dir "${CMAKE_CURRENT_BINARY_DIR}") + set(manifest_out "${manifest_out_dir}/${output_name}.exe.manifest") + + _qt_internal_normalize_project_version() + + get_target_property(project_identifier "${target}" QT_WINDOWS_APP_PROJECT_IDENTIFIER) + if(NOT project_identifier) + message(DEBUG "QT_WINDOWS_APP_PROJECT_IDENTIFIER not set, " + "using com.yourcompany.${target_identifier} as fallback") + set(QT_WINDOWS_APP_PROJECT_IDENTIFIER "com.yourcompany.${target_identifier}") + else() + set(QT_WINDOWS_APP_PROJECT_IDENTIFIER "${project_identifier}") + endif() + + get_target_property(project_executionlevel "${target}" QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL) + if(NOT project_executionlevel) + message(DEBUG "QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL not set, " + "using asInvoker as fallback") + set(QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL "asInvoker") + else() + # Validate value + set(_valid_execution_levels + "asInvoker" + "highestAvailable" + "requireAdministrator" + ) + + if(NOT project_executionlevel IN_LIST _valid_execution_levels) + message(WARNING + "Invalid QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL value: " + "'${project_executionlevel}' for target '${target}'." + "Defaulting to 'asInvoker'." + " Valid values are: asInvoker, highestAvailable, requireAdministrator." + ) + set(QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL "asInvoker") + else() + set(QT_WINDOWS_APP_PROJECT_EXECUTION_LEVEL "${project_executionlevel}") + endif() + endif() + + # Call configure_file to substitute Qt-specific @FOO@ values, not ${FOO} values. + configure_file( + "${manifest_in}" + "${manifest_out}" + @ONLY + ) + + target_sources("${target}" PRIVATE "${manifest_out}") + if(MSVC) + target_link_options(${target} PRIVATE "/MANIFEST:NO") + endif() +endfunction() + function(qt6_add_win_app_sdk target) if(NOT MSVC) message(WARNING diff --git a/local/recipes/qt/qtbase/source/cmake/QtResourceHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtResourceHelpers.cmake index 53d735f6be..02f047678d 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtResourceHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtResourceHelpers.cmake @@ -24,7 +24,7 @@ function(qt_internal_add_resource target resourceName) cmake_parse_arguments(PARSE_ARGV 2 arg "" "PREFIX;LANG;BASE;OUTPUT_TARGETS" - "FILES;OPTIONS") + "FILES") _qt_internal_validate_all_args_are_parsed(arg) _qt_internal_process_resource(${target} ${resourceName} @@ -32,7 +32,6 @@ function(qt_internal_add_resource target resourceName) LANG "${arg_LANG}" BASE "${arg_BASE}" FILES ${arg_FILES} - OPTIONS ${arg_OPTIONS} OUTPUT_TARGETS out_targets ) diff --git a/local/recipes/qt/qtbase/source/cmake/QtSbomHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtSbomHelpers.cmake index 3ee0d4ddd8..de1e905684 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtSbomHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtSbomHelpers.cmake @@ -103,7 +103,7 @@ function(qt_internal_sbom_get_project_spdx_id out_var) set(result "") if(QT_GENERATE_SBOM) - get_cmake_property(project_spdx_id _qt_internal_sbom_project_spdx_id) + _qt_internal_sbom_get_current_project_spdx_id(project_spdx_id) if(project_spdx_id) set(result "${project_spdx_id}") endif() @@ -127,7 +127,7 @@ function(qt_internal_sbom_get_external_document_ref_spdx_id project_name out_var if(QT_GENERATE_SBOM) string(TOLOWER "${project_name}" project_name_lowercase) - _qt_internal_sbom_get_external_document_ref_spdx_id("${project_name_lowercase}" result) + _qt_internal_sbom_compute_external_document_ref_spdx_id("${project_name_lowercase}" result) endif() set(${out_var} "${result}" PARENT_SCOPE) @@ -242,12 +242,12 @@ function(qt_internal_add_sbom_summary_info) qt_internal_is_sbom_option_enabled(QT_SBOM_GENERATE_CYDX_V1_6 value) qt_internal_get_sbom_option_required_suffix(QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6 suffix) - qt_configure_add_summary_entry(ARGS "Generate CyloneDX v1.6" + qt_configure_add_summary_entry(ARGS "Generate CycloneDX v1.6" TYPE "message" MESSAGE "${value}${suffix}") qt_internal_is_sbom_option_enabled(QT_SBOM_VERIFY_CYDX_V1_6 value) qt_internal_get_sbom_option_required_suffix(QT_SBOM_REQUIRE_VERIFY_CYDX_V1_6 suffix) - qt_configure_add_summary_entry(ARGS "Verify CyloneDX v1.6" + qt_configure_add_summary_entry(ARGS "Verify CycloneDX v1.6" TYPE "message" MESSAGE "${value}${suffix}") # Python interpreter info. diff --git a/local/recipes/qt/qtbase/source/cmake/QtTestHelpers.cmake b/local/recipes/qt/qtbase/source/cmake/QtTestHelpers.cmake index 781bdf4143..b4ddafca40 100644 --- a/local/recipes/qt/qtbase/source/cmake/QtTestHelpers.cmake +++ b/local/recipes/qt/qtbase/source/cmake/QtTestHelpers.cmake @@ -682,12 +682,12 @@ function(qt_internal_add_test name) "This is fine if OpenSSL was built statically.") endif() endif() - qt_internal_android_test_runner_arguments("${name}" test_executable extra_test_args) + set(test_executable "$") list(APPEND extra_test_args "--timeout" "${android_timeout}") set(build_environment "") - if(DEFINED ENV{QT_BUILD_ENVIRONMENT}) - set(build_environment "$ENV{QT_BUILD_ENVIRONMENT}") + if(DEFINED ENV{QTEST_ENVIRONMENT}) + set(build_environment "$ENV{QTEST_ENVIRONMENT}") endif() if(QT_ENABLE_VERBOSE_DEPLOYMENT OR build_environment STREQUAL "ci") diff --git a/local/recipes/qt/qtbase/source/coin/axivion/start_analysis.sh b/local/recipes/qt/qtbase/source/coin/axivion/start_analysis.sh index 57f1c4c5e8..4d4f8d7a25 100755 --- a/local/recipes/qt/qtbase/source/coin/axivion/start_analysis.sh +++ b/local/recipes/qt/qtbase/source/coin/axivion/start_analysis.sh @@ -11,6 +11,24 @@ gccsetup --cc gcc --cxx g++ --config "$BAUHAUS_CONFIG" cd "$CAFECC_BASEPATH" BAUHAUS_IR_COMPRESSION=none COMPILE_ONLY=1 cmake -G Ninja -DAXIVION_ANALYSIS_TOOLCHAIN_FILE=/home/qt/bauhaus-suite/profiles/cmake/axivion-launcher-toolchain.cmake -DCMAKE_PREFIX_PATH=/home/qt/work/qt/qtbase/build -DCMAKE_PROJECT_INCLUDE_BEFORE=/home/qt/bauhaus-suite/profiles/cmake/axivion-before-project-hook.cmake -B build -S . --fresh cmake --build build -j4 + +ROOT_DIR=src +MAGIC="Qt-Security score:critical" + +INCLUDE_FILES="" + +while IFS= read -r file; do + if [ -z "$INCLUDE_FILES" ]; then + INCLUDE_FILES="$file" + else + INCLUDE_FILES="$INCLUDE_FILES:$file" + fi +done < + Failed to run tests. enable_if: condition: runtime env_var: COIN_CTEST_IGNORE_EXIT_CODE not_equals_value: "1" - instructions: - - type: ExecuteCommand - command: "{{.Env.TESTS_ENV_PREFIX}} ctest {{.Env.CTEST_ARGS}}" - executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution - ignoreExitCode: false - maxTimeInSeconds: 14400 - maxTimeBetweenOutput: 14400 - userMessageOnFailure: > - Failed to run tests. - - type: ExecuteCommand - command: > - cmake -E copy - Testing{{.Env.CI_PATH_SEP}}Temporary{{.Env.CI_PATH_SEP}}LastTest.log - {{.Env.COIN_CTEST_RESULTSDIR}}{{.Env.CI_PATH_SEP}}CTest.log - executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution - ignoreExitCode: false - userMessageOnFailure: > - Failed to copy LastTest.log to testresults directory. - executeOn: always - maxTimeInSeconds: 20 - maxTimeBetweenOutput: 20 - - type: Group + - type: ExecuteCommand + command: "{{.Env.TESTS_ENV_PREFIX}} ctest {{.Env.CTEST_ARGS}}" + executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution + ignoreExitCode: true + maxTimeInSeconds: 14400 + maxTimeBetweenOutput: 14400 + userMessageOnFailure: > + Failed to run tests. enable_if: condition: runtime env_var: COIN_CTEST_IGNORE_EXIT_CODE equals_value: "1" - instructions: - - type: ExecuteCommand - command: "{{.Env.TESTS_ENV_PREFIX}} ctest {{.Env.CTEST_ARGS}}" - executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution - ignoreExitCode: true - maxTimeInSeconds: 14400 - maxTimeBetweenOutput: 14400 - userMessageOnFailure: > - Failed to run tests. - - type: ExecuteCommand - command: > - cmake -E copy - Testing{{.Env.CI_PATH_SEP}}Temporary{{.Env.CI_PATH_SEP}}LastTest.log - {{.Env.COIN_CTEST_RESULTSDIR}}{{.Env.CI_PATH_SEP}}CTest.log - executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution - ignoreExitCode: true - userMessageOnFailure: > - Failed to copy LastTest.log to testresults directory. - executeOn: always + + - type: ExecuteCommand + instructionName: "Copy ctest log" + command: > + cmake -E copy + Testing{{.Env.CI_PATH_SEP}}Temporary{{.Env.CI_PATH_SEP}}LastTest.log + {{.Env.COIN_CTEST_RESULTSDIR}} + executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution + userMessageOnFailure: > + Failed to copy LastTest.log to testresults directory. + executeOn: always + maxTimeInSeconds: 60 + maxTimeBetweenOutput: 60 + - type: ExecuteCommand + command: > + cmake -E copy + Testing{{.Env.CI_PATH_SEP}}Temporary{{.Env.CI_PATH_SEP}}LastTest.log.tmp + {{.Env.COIN_CTEST_RESULTSDIR}} + executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution + userMessageOnFailure: > + Failed to copy LastTest.log.tmp to testresults directory. + executeOn: failure + executeOnTarget: Copy ctest log + resetError: target + maxTimeInSeconds: 60 + maxTimeBetweenOutput: 60 - type: Group instructions: diff --git a/local/recipes/qt/qtbase/source/coin/instructions/prepare_building_env.yaml b/local/recipes/qt/qtbase/source/coin/instructions/prepare_building_env.yaml index 3e7f49ce46..f4c5b78f95 100644 --- a/local/recipes/qt/qtbase/source/coin/instructions/prepare_building_env.yaml +++ b/local/recipes/qt/qtbase/source/coin/instructions/prepare_building_env.yaml @@ -310,7 +310,13 @@ instructions: condition: property property: host.compiler equals_value: MSVC2022 - + - type: EnvironmentVariable + variableName: VC_SCRIPT + variableValue: "%ProgramFiles%\\Microsoft Visual Studio\\18\\Professional\\VC\\Auxiliary\\Build\\vcvarsall.bat" + enable_if: + condition: property + property: host.compiler + equals_value: MSVC2026 # With MSVC we need setup the environment before every subprocess call, the group below creates a script that # does it. It is enough to prepand it to every call (it is safe to add it even on other OSes) @@ -555,8 +561,12 @@ instructions: variableValue: >- -DQT_GENERATE_SBOM=ON -DQT_GENERATE_SOURCE_SBOM=ON - -DQT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON + -DQT_SBOM_VERIFY_SPDX_V2=ON + -DQT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON=ON + -DQT_SBOM_REQUIRE_VERIFY_SPDX_V2=ON -DQT_SBOM_VERIFY_CYDX_V1_6=ON + -DQT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON + -DQT_SBOM_REQUIRE_VERIFY_CYDX_V1_6=ON - type: AppendToEnvironmentVariable variableName: COMMON_CMAKE_ARGS variableValue: " {{.Env.SBOM_COMMON_ARGS}} " diff --git a/local/recipes/qt/qtbase/source/configure.cmake b/local/recipes/qt/qtbase/source/configure.cmake index 23575f937c..50c6710c6d 100644 --- a/local/recipes/qt/qtbase/source/configure.cmake +++ b/local/recipes/qt/qtbase/source/configure.cmake @@ -1306,12 +1306,17 @@ qt_feature("coverage" CONDITION QT_FEATURE_coverage_gcov ) -qt_feature("android_16kb_pages" +# Mark the feature as PRIVATE because we want it to be exported, but we don't want modifications +# in the public qconfig.h header in a patch release. +qt_feature("android_16kb_pages" PRIVATE LABEL "Using 16KB page sizes in Android" CONDITION ANDROID AND (((CMAKE_ANDROID_NDK_VERSION VERSION_GREATER_EQUAL "25.0.0")) AND ((CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") OR (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64"))) ) +# The feature is saved into the public QT_CONFIG var in the qt_lib_core.pri file, to ensure it's +# available automatically for testing with qtConfig() in all user projects. +qt_feature_config("android_16kb_pages" QMAKE_PUBLIC_QT_CONFIG) qt_configure_add_summary_build_type_and_config() qt_configure_add_summary_section(NAME "Build options") diff --git a/local/recipes/qt/qtbase/source/doc/global/externalsites/qt-webpages.qdoc b/local/recipes/qt/qtbase/source/doc/global/externalsites/qt-webpages.qdoc index 6cbf5f377b..d228602b7e 100644 --- a/local/recipes/qt/qtbase/source/doc/global/externalsites/qt-webpages.qdoc +++ b/local/recipes/qt/qtbase/source/doc/global/externalsites/qt-webpages.qdoc @@ -1,21 +1,25 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! - \externalpage http://qt.io/ + \externalpage https://qt.io/ \title Qt Homepage */ /*! - \externalpage http://bugreports.qt.io + \externalpage https://qt-project.atlassian.net/jira/ \title Qt Bug Tracker */ /*! - \externalpage http://qt.io/download + \externalpage https://qt.io/download \title Downloads */ /*! - \externalpage http://www.qt.io/about-us/ + \externalpage https://www.qt.io/about-us/ \title The Qt Company */ +/*! + \externalpage https://www.qt.io/about-us/ + \title The Qt Group +*/ /*! \externalpage https://code.qt.io/ \title Public Qt Repository diff --git a/local/recipes/qt/qtbase/source/doc/global/macros.qdocconf b/local/recipes/qt/qtbase/source/doc/global/macros.qdocconf index 244331c2c1..c4486ef8dd 100644 --- a/local/recipes/qt/qtbase/source/doc/global/macros.qdocconf +++ b/local/recipes/qt/qtbase/source/doc/global/macros.qdocconf @@ -57,7 +57,6 @@ macro.examplecategory = "\\meta category {\1}\n\\ingroup category \1" macro.B2Q = "Boot to Qt" macro.B2QSS = "Boot to Qt Software Stack" -macro.B2QST = "Boot to Qt Startup Screen" macro.IFW = "Qt Installer Framework" macro.Q4A = "Qt for Android" macro.QA = "Qt Assistant" @@ -81,6 +80,7 @@ macro.QOI = "Qt Online Installer" macro.QQEM = "Qt Quick Effect Maker" macro.QQV = "Qt QML Viewer" macro.QtAA = "Qt for Android Automotive" +macro.QTOB = "Qt Onboard" macro.QUL = "Qt Quick Ultralite" macro.QtTAS = "Qt Tools for Android Studio" diff --git a/local/recipes/qt/qtbase/source/examples/corelib/platform/androidnotifier/android/AndroidManifest.xml b/local/recipes/qt/qtbase/source/examples/corelib/platform/androidnotifier/android/AndroidManifest.xml index 1d3cf1325b..4e7ce437b5 100644 --- a/local/recipes/qt/qtbase/source/examples/corelib/platform/androidnotifier/android/AndroidManifest.xml +++ b/local/recipes/qt/qtbase/source/examples/corelib/platform/androidnotifier/android/AndroidManifest.xml @@ -16,7 +16,6 @@ android:smallScreens="true" /> to hold our data + and a QRangeModel operating on it. \section1 Window Class Implementation - The constructor of the \c Window class can be explained in three parts. + The constructor of the \c Window class can be explained in several parts. In the first part, we set up the widgets used for the user interface: \snippet itemviews/combowidgetmapper/window.cpp Set up widgets + The person list is populated using an initalizer list, which is then + passed to the QRangeModel: + + \snippet itemviews/combowidgetmapper/window.cpp Set up the model + Note that we set up the mapping the combo box in the same way as for other - widgets, but that we apply its own model to it so that it will display - data from its own model, the \c typeModel, rather than from the model - containing data about each person. + widgets, but that we apply its own model holding information about the + types of address to it, so that it will display the address type string + rather than the data from the model containing data about each person: + + \snippet itemviews/combowidgetmapper/window.cpp Set up type combo box Next, we set up the widget mapper, relating each input widget to a column in the model specified by the call to \l{QDataWidgetMapper::}{setModel()}: @@ -64,20 +79,6 @@ \snippet itemviews/combowidgetmapper/window.cpp Set up connections and layouts - The model is initialized in the window's \c{setupModel()} function. Here, - we create a standard model with 5 rows and 3 columns. In each row, we - insert a name, address, and a value that indicates the type of address. - The address types are stored in a string list model. - - \snippet itemviews/combowidgetmapper/window.cpp Set up the model - - As we insert each row into the model, like a record in a database, we - store values that correspond to items in \c typeModel for each person's - address type. When the widget mapper reads these values from the final - column of each row, it will need to use them as references to values in - \c typeModel, as shown in the following diagram. This is where the - delegate is used. - \image widgetmapper-combo-mapping.png {Mapping of the model to the view using a delegate} diff --git a/local/recipes/qt/qtbase/source/examples/widgets/doc/src/customsortfiltermodel.qdoc b/local/recipes/qt/qtbase/source/examples/widgets/doc/src/customsortfiltermodel.qdoc index b6ff8e7b48..2bd39d1599 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/doc/src/customsortfiltermodel.qdoc +++ b/local/recipes/qt/qtbase/source/examples/widgets/doc/src/customsortfiltermodel.qdoc @@ -189,13 +189,13 @@ data structure: \snippet itemviews/customsortfiltermodel/window.cpp 3 - \snippet itemviews/customsortfiltermodel/window.cpp 4 Note that whenever the user changes one of the filtering options, we must explicitly reapply the filter. This is done by connecting the various editors to functions that update the proxy model. - \snippet itemviews/customsortfiltermodel/window.cpp 5 + \snippet itemviews/customsortfiltermodel/window.cpp 4 + The sorting will be handled by the view. All we have to do is to enable sorting for our proxy view by setting the @@ -203,12 +203,14 @@ default). Then we add all the filtering widgets and the proxy view to a layout that we install on a corresponding group box. - \snippet itemviews/customsortfiltermodel/window.cpp 6 + \snippet itemviews/customsortfiltermodel/window.cpp 5 Finally, after putting our two group boxes into another layout that we install on our main application widget, we customize the application window. + \snippet itemviews/customsortfiltermodel/window.cpp 6 + As mentioned above, we create the source model in the \c main () function, calling the \c Window::setSourceModel() function to make the application use it: @@ -253,14 +255,15 @@ model by creating the model in the \c main () function. First we create the application, then we create the source model: - \snippet itemviews/customsortfiltermodel/main.cpp 0 + \snippet itemviews/customsortfiltermodel/main.cpp 1 - The \c createMailModel() function is a convenience function - provided to simplify the constructor. All it does is to create and - return a model describing a collection of emails. The model is an - instance of the QStandardItemModel class, i.e., a generic model - for storing custom data typically used as a repository for - standard Qt data types. Each mail description is added to the - model using \c addMail(), another convenience function. See \c - {itemviews/customsortfiltermodel/main.cpp} for details. + We create a class \c MailModel, which inherits QRangeModel and + reimplements QAbstractItemView::headerData() to return the correct section + headings. It is populated from an array of struct \c MailHeader. + \c MailHeader is declared to be a \c Q_GADGET with properties to be used + by QRangeModel: + + \snippet itemviews/customsortfiltermodel/mailheader.h 0 + + \snippet itemviews/customsortfiltermodel/main.cpp 0 */ diff --git a/local/recipes/qt/qtbase/source/examples/widgets/gallery/widgetgallery.cpp b/local/recipes/qt/qtbase/source/examples/widgets/gallery/widgetgallery.cpp index e2ffec50e8..4ddc5da183 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/gallery/widgetgallery.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/gallery/widgetgallery.cpp @@ -153,6 +153,10 @@ WidgetGallery::WidgetGallery(QWidget *parent) QGuiApplication::styleHints()->setColorScheme(static_cast(index)); }); + connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, [colorSchemeComboBox](Qt::ColorScheme colorScheme) { + colorSchemeComboBox->setCurrentIndex(static_cast(colorScheme)); + }); + const QKeySequence helpKeySequence(QKeySequence::HelpContents); const QString helpText = tr("Press %1 over a widget to see Documentation") .arg(helpKeySequence.toString(QKeySequence::NativeText)); diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/CMakeLists.txt b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/CMakeLists.txt index 91e9cd03c9..33030bbca9 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/CMakeLists.txt @@ -11,6 +11,7 @@ qt_standard_project_setup() qt_add_executable(addressbook adddialog.cpp adddialog.h addresswidget.cpp addresswidget.h + contact.h main.cpp mainwindow.cpp mainwindow.h newaddresstab.cpp newaddresstab.h diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.cpp index 96877661bb..2c3599bf0d 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.cpp @@ -2,58 +2,63 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "adddialog.h" +#include "contact.h" -#include +#include +#include +#include +#include +#include +#include +#include //! [0] AddDialog::AddDialog(QWidget *parent) : QDialog(parent), + buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this)), nameText(new QLineEdit), - addressText(new QTextEdit) + addressText(new QPlainTextEdit) { - auto nameLabel = new QLabel(tr("Name")); - auto addressLabel = new QLabel(tr("Address")); - auto okButton = new QPushButton(tr("OK")); - auto cancelButton = new QPushButton(tr("Cancel")); + auto *formLayout = new QFormLayout; + formLayout->addRow(tr("Name"), nameText); + formLayout->addRow(tr("Address"), addressText); - auto gLayout = new QGridLayout; - gLayout->setColumnStretch(1, 2); - gLayout->addWidget(nameLabel, 0, 0); - gLayout->addWidget(nameText, 0, 1); + auto *mainLayout = new QVBoxLayout(this); + mainLayout->addLayout(formLayout); + mainLayout->addWidget(buttonBox); - gLayout->addWidget(addressLabel, 1, 0, Qt::AlignLeft|Qt::AlignTop); - gLayout->addWidget(addressText, 1, 1, Qt::AlignLeft); - - auto buttonLayout = new QHBoxLayout; - buttonLayout->addWidget(okButton); - buttonLayout->addWidget(cancelButton); - - gLayout->addLayout(buttonLayout, 2, 1, Qt::AlignRight); - - auto mainLayout = new QVBoxLayout; - mainLayout->addLayout(gLayout); - setLayout(mainLayout); - - connect(okButton, &QAbstractButton::clicked, this, &QDialog::accept); - connect(cancelButton, &QAbstractButton::clicked, this, &QDialog::reject); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(nameText, &QLineEdit::textChanged, this, &AddDialog::updateEnabled); + connect(addressText, &QPlainTextEdit::textChanged, this, &AddDialog::updateEnabled); setWindowTitle(tr("Add a Contact")); + + updateEnabled(); } -QString AddDialog::name() const +void AddDialog::updateEnabled() { - return nameText->text(); + Contact c = contact(); + const bool valid = !c.name.isEmpty() && c.name.front().isLetter() && !c.address.isEmpty(); + buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } -QString AddDialog::address() const +Contact AddDialog::contact() const { - return addressText->toPlainText(); + return { nameText->text().trimmed(), addressText->toPlainText().trimmed() }; } -void AddDialog::editAddress(const QString &name, const QString &address) +void AddDialog::setContact(const Contact &c) +{ + nameText->setText(c.name); + addressText->setPlainText(c.address); + updateEnabled(); +} + +void AddDialog::editAddress(const Contact &c) { nameText->setReadOnly(true); - nameText->setText(name); - addressText->setPlainText(address); + setContact(c); } //! [0] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.h index 4984e86ddc..d0c66f3d1b 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/adddialog.h @@ -7,27 +7,34 @@ #include QT_BEGIN_NAMESPACE +class QDialogButtonBox; class QLabel; -class QPushButton; -class QTextEdit; +class QPlainTextEdit; class QLineEdit; QT_END_NAMESPACE +struct Contact; + //! [0] class AddDialog : public QDialog { Q_OBJECT public: - AddDialog(QWidget *parent = nullptr); + explicit AddDialog(QWidget *parent = nullptr); - QString name() const; - QString address() const; - void editAddress(const QString &name, const QString &address); + Contact contact() const; + void setContact(const Contact &c); + + void editAddress(const Contact &c); + +private slots: + void updateEnabled(); private: + QDialogButtonBox *buttonBox; QLineEdit *nameText; - QTextEdit *addressText; + QPlainTextEdit *addressText; }; //! [0] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addressbook.pro b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addressbook.pro index 498b2574ce..64c39bee66 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addressbook.pro +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addressbook.pro @@ -9,6 +9,7 @@ SOURCES = adddialog.cpp \ tablemodel.cpp HEADERS = adddialog.h \ addresswidget.h \ + contact.h \ mainwindow.h \ newaddresstab.h \ tablemodel.h diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.cpp index 5b226793e4..b783c0f955 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.cpp @@ -3,8 +3,33 @@ #include "addresswidget.h" #include "adddialog.h" +#include "newaddresstab.h" +#include "tablemodel.h" -#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Qt::StringLiterals; + +QString AddressWidget::fileName() +{ + static const QString result = QStandardPaths::standardLocations(QStandardPaths::TempLocation).value(0) + + "/addressbook.dat"_L1; + return result; +} //! [0] AddressWidget::AddressWidget(QWidget *parent) @@ -12,8 +37,7 @@ AddressWidget::AddressWidget(QWidget *parent) table(new TableModel(this)), newAddressTab(new NewAddressTab(this)) { - connect(newAddressTab, &NewAddressTab::sendDetails, - this, &AddressWidget::addEntry); + connect(newAddressTab, &NewAddressTab::triggered, this, &AddressWidget::showAddEntryDialog); addTab(newAddressTab, tr("Address Book")); @@ -24,30 +48,33 @@ AddressWidget::AddressWidget(QWidget *parent) //! [2] void AddressWidget::showAddEntryDialog() { - AddDialog aDialog; + AddDialog aDialog(this); - if (aDialog.exec()) - addEntry(aDialog.name(), aDialog.address()); + if (aDialog.exec() == QDialog::Accepted) + addEntry(aDialog.contact()); } //! [2] //! [3] -void AddressWidget::addEntry(const QString &name, const QString &address) +void AddressWidget::addEntry(const Contact &contact) { - if (!name.front().isLetter()) { - QMessageBox::information(this, tr("Invalid name"), - tr("The name must start with a letter.")); - } else if (!table->getContacts().contains({ name, address })) { - table->insertRows(0, 1, QModelIndex()); - - QModelIndex index = table->index(0, 0, QModelIndex()); - table->setData(index, name, Qt::EditRole); - index = table->index(0, 1, QModelIndex()); - table->setData(index, address, Qt::EditRole); - removeTab(indexOf(newAddressTab)); - } else { + if (table->getContacts().contains(contact)) { QMessageBox::information(this, tr("Duplicate Name"), - tr("The name \"%1\" already exists.").arg(name)); + tr("The name \"%1\" already exists.").arg(contact.name)); + return; + } + + table->insertRows(0, 1); + table->setData(table->index(0, 0), contact.name, Qt::EditRole); + table->setData(table->index(0, 1), contact.address, Qt::EditRole); + removeTab(indexOf(newAddressTab)); + + const QChar firstChar = contact.name.at(0).toUpper(); + for (int t = 0, tabCount = count(); t < tabCount; ++t) { + if (tabText(t).contains(firstChar)) { + setCurrentIndex(t); + break; + } } } //! [3] @@ -55,37 +82,35 @@ void AddressWidget::addEntry(const QString &name, const QString &address) //! [4a] void AddressWidget::editEntry() { - QTableView *temp = static_cast(currentWidget()); - QSortFilterProxyModel *proxy = static_cast(temp->model()); - QItemSelectionModel *selectionModel = temp->selectionModel(); + auto *tableView = static_cast(currentWidget()); + auto *proxy = static_cast(tableView->model()); + QItemSelectionModel *selectionModel = tableView->selectionModel(); const QModelIndexList indexes = selectionModel->selectedRows(); - QString name; - QString address; - int row = -1; + if (indexes.isEmpty()) + return; - for (const QModelIndex &index : indexes) { - row = proxy->mapToSource(index).row(); - QModelIndex nameIndex = table->index(row, 0, QModelIndex()); - QVariant varName = table->data(nameIndex, Qt::DisplayRole); - name = varName.toString(); + const int row = proxy->mapToSource(indexes.constFirst()).row(); - QModelIndex addressIndex = table->index(row, 1, QModelIndex()); - QVariant varAddr = table->data(addressIndex, Qt::DisplayRole); - address = varAddr.toString(); - } + Contact contact; + QModelIndex nameIndex = table->index(row, 0); + QVariant varName = table->data(nameIndex, Qt::DisplayRole); + contact.name = varName.toString(); + QModelIndex addressIndex = table->index(row, 1); + QVariant varAddr = table->data(addressIndex, Qt::DisplayRole); + contact.address = varAddr.toString(); //! [4a] //! [4b] - AddDialog aDialog; + AddDialog aDialog(this); aDialog.setWindowTitle(tr("Edit a Contact")); - aDialog.editAddress(name, address); + aDialog.editAddress(contact); - if (aDialog.exec()) { - const QString newAddress = aDialog.address(); - if (newAddress != address) { - const QModelIndex index = table->index(row, 1, QModelIndex()); - table->setData(index, newAddress, Qt::EditRole); + if (aDialog.exec() == QDialog::Accepted) { + const Contact newContact = aDialog.contact(); + if (newContact != contact) { + const QModelIndex index = table->index(row, 1); + table->setData(index, newContact.address, Qt::EditRole); } } } @@ -94,18 +119,18 @@ void AddressWidget::editEntry() //! [5] void AddressWidget::removeEntry() { - QTableView *temp = static_cast(currentWidget()); - QSortFilterProxyModel *proxy = static_cast(temp->model()); - QItemSelectionModel *selectionModel = temp->selectionModel(); + auto *tableView = static_cast(currentWidget()); + auto *proxy = static_cast(tableView->model()); + QItemSelectionModel *selectionModel = tableView->selectionModel(); const QModelIndexList indexes = selectionModel->selectedRows(); + if (indexes.isEmpty()) + return; - for (QModelIndex index : indexes) { - int row = proxy->mapToSource(index).row(); - table->removeRows(row, 1, QModelIndex()); - } + const int row = proxy->mapToSource(indexes.constFirst()).row(); + table->removeRows(row, 1); - if (table->rowCount(QModelIndex()) == 0) + if (table->rowCount() == 0) insertTab(0, newAddressTab, tr("Address Book")); } //! [5] @@ -113,7 +138,6 @@ void AddressWidget::removeEntry() //! [1] void AddressWidget::setupTabs() { - using namespace Qt::StringLiterals; const auto groups = { "ABC"_L1, "DEF"_L1, "GHI"_L1, "JKL"_L1, "MNO"_L1, "PQR"_L1, "STU"_L1, "VW"_L1, "XYZ"_L1 }; @@ -121,12 +145,12 @@ void AddressWidget::setupTabs() const auto regExp = QRegularExpression(QLatin1StringView("^[%1].*").arg(str), QRegularExpression::CaseInsensitiveOption); - auto proxyModel = new QSortFilterProxyModel(this); + auto *proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(table); proxyModel->setFilterRegularExpression(regExp); proxyModel->setFilterKeyColumn(0); - QTableView *tableView = new QTableView; + auto *tableView = new QTableView; tableView->setModel(proxyModel); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->horizontalHeader()->setStretchLastSection(true); @@ -149,14 +173,15 @@ void AddressWidget::setupTabs() //! [1] //! [7] -void AddressWidget::readFromFile() +bool AddressWidget::readFromFile() { - QFile file(fileName); + QFile file(fileName()); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::information(this, tr("Unable to open file"), - file.errorString()); - return; + tr("Cannot open %1: %2").arg(QDir::toNativeSeparators(fileName()), + file.errorString())); + return false; } QList contacts; @@ -166,24 +191,32 @@ void AddressWidget::readFromFile() if (contacts.isEmpty()) { QMessageBox::information(this, tr("No contacts in file"), tr("The file you are attempting to open contains no contacts.")); - } else { - for (const auto &contact: std::as_const(contacts)) - addEntry(contact.name, contact.address); } + + for (const auto &contact : std::as_const(contacts)) + addEntry(contact); + + return true; } //! [7] //! [6] -void AddressWidget::writeToFile() +bool AddressWidget::writeToFile() { - QFile file(fileName); + QFile file(fileName()); if (!file.open(QIODevice::WriteOnly)) { - QMessageBox::information(this, tr("Unable to open file"), file.errorString()); - return; + QMessageBox::information(this, tr("Unable to open file"), + tr("Cannot write to %1: %2").arg(QDir::toNativeSeparators(fileName()), + file.errorString())); + return false; } + auto sortedContacts = table->getContacts(); + std::sort(sortedContacts.begin(), sortedContacts.end()); + QDataStream out(&file); - out << table->getContacts(); + out << sortedContacts; + return true; } //! [6] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.h index c5c710286a..a66dc6737d 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/addresswidget.h @@ -4,31 +4,33 @@ #ifndef ADDRESSWIDGET_H #define ADDRESSWIDGET_H -#include "newaddresstab.h" -#include "tablemodel.h" - -#include #include -#include QT_BEGIN_NAMESPACE class QSortFilterProxyModel; -class QItemSelectionModel; +class QItemSelection; QT_END_NAMESPACE +struct Contact; +class NewAddressTab; +class TableModel; + //! [0] class AddressWidget : public QTabWidget { Q_OBJECT public: - AddressWidget(QWidget *parent = nullptr); - void readFromFile(); - void writeToFile(); + explicit AddressWidget(QWidget *parent = nullptr); + + bool readFromFile(); + bool writeToFile(); + + static QString fileName(); public slots: void showAddEntryDialog(); - void addEntry(const QString &name, const QString &address); + void addEntry(const Contact &contact); void editEntry(); void removeEntry(); @@ -38,9 +40,6 @@ signals: private: void setupTabs(); - inline static QString fileName = - QStandardPaths::standardLocations(QStandardPaths::TempLocation).value(0) - + QStringLiteral("/addressbook.dat"); TableModel *table; NewAddressTab *newAddressTab; }; diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/main.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/main.cpp index 8aaf0fe348..4f7bef4813 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/main.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/main.cpp @@ -5,12 +5,18 @@ #include +#include + +#include + //! [0] int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow mw; + const auto availableGeometry = mw.screen()->availableGeometry(); + mw.resize(availableGeometry.width() / 3, availableGeometry.height() / 3); mw.show(); - return app.exec(); + return QCoreApplication::exec(); } //! [0] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/mainwindow.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/mainwindow.cpp index ce37b523f3..9d5bf4dcce 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/mainwindow.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/mainwindow.cpp @@ -6,6 +6,14 @@ #include #include #include +#include + +#include +#include + +#include +#include +#include //! [0] MainWindow::MainWindow() @@ -23,24 +31,31 @@ void MainWindow::createMenus() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); - QAction *openAct = new QAction(tr("&Open..."), this); + auto *openAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpen), + tr("&Open..."), this); + openAct->setShortcut(QKeySequence(QKeySequence::Open)); fileMenu->addAction(openAct); connect(openAct, &QAction::triggered, this, &MainWindow::openFile); //! [1a] - QAction *saveAct = new QAction(tr("&Save"), this); + auto *saveAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSave), + tr("&Save"), this); + saveAct->setShortcut(QKeySequence(QKeySequence::Save)); fileMenu->addAction(saveAct); connect(saveAct, &QAction::triggered, this, &MainWindow::saveFile); fileMenu->addSeparator(); - QAction *exitAct = new QAction(tr("E&xit"), this); + auto *exitAct = new QAction(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit), + tr("E&xit"), this); + exitAct->setShortcut(QKeySequence(QKeySequence::Quit)); fileMenu->addAction(exitAct); connect(exitAct, &QAction::triggered, this, &QWidget::close); QMenu *toolMenu = menuBar()->addMenu(tr("&Tools")); - QAction *addAct = new QAction(tr("&Add Entry..."), this); + auto *addAct = new QAction(tr("&Add Entry..."), this); + addAct->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_A)); toolMenu->addAction(addAct); connect(addAct, &QAction::triggered, addressWidget, &AddressWidget::showAddEntryDialog); @@ -59,35 +74,32 @@ void MainWindow::createMenus() connect(removeAct, &QAction::triggered, addressWidget, &AddressWidget::removeEntry); connect(addressWidget, &AddressWidget::selectionChanged, - this, &MainWindow::updateActions); + this, &MainWindow::updateActions); } //! [1b] //! [2] void MainWindow::openFile() { - addressWidget->readFromFile(); + if (addressWidget->readFromFile()) + statusBar()->showMessage(tr("Read %1").arg(QDir::toNativeSeparators(AddressWidget::fileName()))); } //! [2] //! [3] void MainWindow::saveFile() { - addressWidget->writeToFile(); + if (addressWidget->writeToFile()) + statusBar()->showMessage(tr("Wrote %1").arg(QDir::toNativeSeparators(AddressWidget::fileName()))); } //! [3] //! [4] void MainWindow::updateActions(const QItemSelection &selection) { - QModelIndexList indexes = selection.indexes(); + const QModelIndexList indexes = selection.indexes(); - if (!indexes.isEmpty()) { - removeAct->setEnabled(true); - editAct->setEnabled(true); - } else { - removeAct->setEnabled(false); - editAct->setEnabled(false); - } + removeAct->setEnabled(!indexes.isEmpty()); + editAct->setEnabled(!indexes.isEmpty()); } //! [4] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.cpp index 4ab85aadaf..35f88335ea 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.cpp @@ -2,35 +2,24 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "newaddresstab.h" -#include "adddialog.h" -#include +#include +#include +#include //! [0] NewAddressTab::NewAddressTab(QWidget *parent) : QWidget(parent) { - auto descriptionLabel = new QLabel(tr("There are currently no contacts in your address book. " - "\nClick Add to add new contacts.")); + auto *descriptionLabel = new QLabel(tr("There are currently no contacts in your address book. " + "\nClick Add to add new contacts.")); - auto addButton = new QPushButton(tr("Add")); + auto *addButton = new QPushButton(tr("Add")); - connect(addButton, &QAbstractButton::clicked, this, &NewAddressTab::addEntry); + connect(addButton, &QAbstractButton::clicked, this, &NewAddressTab::triggered); - auto mainLayout = new QVBoxLayout; - mainLayout->addWidget(descriptionLabel); + auto *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(descriptionLabel, 0, Qt::AlignCenter); mainLayout->addWidget(addButton, 0, Qt::AlignCenter); - - setLayout(mainLayout); } //! [0] - -//! [1] -void NewAddressTab::addEntry() -{ - AddDialog aDialog; - - if (aDialog.exec()) - emit sendDetails(aDialog.name(), aDialog.address()); -} -//! [1] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.h index 3f21a7271b..22fb58485e 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/newaddresstab.h @@ -6,25 +6,16 @@ #include -QT_BEGIN_NAMESPACE -class QLabel; -class QPushButton; -class QVBoxLayout; -QT_END_NAMESPACE - //! [0] class NewAddressTab : public QWidget { Q_OBJECT public: - NewAddressTab(QWidget *parent = nullptr); - -public slots: - void addEntry(); + explicit NewAddressTab(QWidget *parent = nullptr); signals: - void sendDetails(const QString &name, const QString &address); + void triggered(); }; //! [0] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.cpp index 2d7ab69eb8..dc394dcb07 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.cpp @@ -31,10 +31,10 @@ int TableModel::columnCount(const QModelIndex &parent) const QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) - return QVariant(); + return {}; if (index.row() >= contacts.size() || index.row() < 0) - return QVariant(); + return {}; if (role == Qt::DisplayRole) { const auto &contact = contacts.at(index.row()); @@ -48,17 +48,14 @@ QVariant TableModel::data(const QModelIndex &index, int role) const break; } } - return QVariant(); + return {}; } //! [2] //! [3] QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Name"); @@ -68,7 +65,7 @@ QVariant TableModel::headerData(int section, Qt::Orientation orientation, int ro break; } } - return QVariant(); + return {}; } //! [3] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.h index 4a9778c7b9..f8fc052c6c 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/addressbook/tablemodel.h @@ -4,48 +4,29 @@ #ifndef TABLEMODEL_H #define TABLEMODEL_H +#include "contact.h" + #include #include //! [0] - -struct Contact -{ - QString name; - QString address; - - bool operator==(const Contact &other) const - { - return name == other.name && address == other.address; - } -}; - -inline QDataStream &operator<<(QDataStream &stream, const Contact &contact) -{ - return stream << contact.name << contact.address; -} - -inline QDataStream &operator>>(QDataStream &stream, Contact &contact) -{ - return stream >> contact.name >> contact.address; -} - class TableModel : public QAbstractTableModel { Q_OBJECT public: - TableModel(QObject *parent = nullptr); + explicit TableModel(QObject *parent = nullptr); TableModel(const QList &contacts, QObject *parent = nullptr); - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + int rowCount(const QModelIndex &parent = {}) const override; + int columnCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; - bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; + bool insertRows(int position, int rows, const QModelIndex &index = {}) override; + bool removeRows(int position, int rows, const QModelIndex &index = {}) override; + const QList &getContacts() const; private: diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/CMakeLists.txt b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/CMakeLists.txt index da15c4c196..929b567647 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/CMakeLists.txt @@ -10,7 +10,7 @@ qt_standard_project_setup() qt_add_executable(basicsortfiltermodel main.cpp - window.cpp window.h + window.cpp window.h mailheader.h ) set_target_properties(basicsortfiltermodel PROPERTIES diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/basicsortfiltermodel.pro b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/basicsortfiltermodel.pro index c8087666fe..be6ef0043d 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/basicsortfiltermodel.pro +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/basicsortfiltermodel.pro @@ -1,7 +1,8 @@ QT += widgets requires(qtConfig(combobox)) -HEADERS = window.h +HEADERS = window.h \ + mailheader.h SOURCES = main.cpp \ window.cpp diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/main.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/main.cpp index db132760af..caf29fd623 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/main.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/main.cpp @@ -1,58 +1,72 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include "mailheader.h" #include "window.h" -#include -#include -#include +#include -void addMail(QAbstractItemModel *model, const QString &subject, - const QString &sender, const QDateTime &date) +#include + +#include + +using namespace Qt::StringLiterals; + +class MailModel : public QRangeModel { - model->insertRow(0); - model->setData(model->index(0, 0), subject); - model->setData(model->index(0, 1), sender); - model->setData(model->index(0, 2), date); -} +public: + explicit MailModel(QObject *parent = nullptr) : QRangeModel(mails, parent) {} -QAbstractItemModel *createMailModel(QObject *parent) -{ - QStandardItemModel *model = new QStandardItemModel(0, 3, parent); + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override + { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: + return Window::tr("Subject"); + case 1: + return Window::tr("Sender"); + case 2: + return Window::tr("Date"); + default: + break; + } + } + return QRangeModel::headerData(section, orientation, role); + } - model->setHeaderData(0, Qt::Horizontal, QObject::tr("Subject")); - model->setHeaderData(1, Qt::Horizontal, QObject::tr("Sender")); - model->setHeaderData(2, Qt::Horizontal, QObject::tr("Date")); +private: + static const std::array mails; +}; - addMail(model, "Happy New Year!", "Grace K. ", - QDateTime(QDate(2006, 12, 31), QTime(17, 03))); - addMail(model, "Radically new concept", "Grace K. ", - QDateTime(QDate(2006, 12, 22), QTime(9, 44))); - addMail(model, "Accounts", "pascale@nospam.com", - QDateTime(QDate(2006, 12, 31), QTime(12, 50))); - addMail(model, "Expenses", "Joe Bloggs ", - QDateTime(QDate(2006, 12, 25), QTime(11, 39))); - addMail(model, "Re: Expenses", "Andy ", - QDateTime(QDate(2007, 01, 02), QTime(16, 05))); - addMail(model, "Re: Accounts", "Joe Bloggs ", - QDateTime(QDate(2007, 01, 03), QTime(14, 18))); - addMail(model, "Re: Accounts", "Andy ", - QDateTime(QDate(2007, 01, 03), QTime(14, 26))); - addMail(model, "Sports", "Linda Smith ", - QDateTime(QDate(2007, 01, 05), QTime(11, 33))); - addMail(model, "AW: Sports", "Rolf Newschweinstein ", - QDateTime(QDate(2007, 01, 05), QTime(12, 00))); - addMail(model, "RE: Sports", "Petra Schmidt ", - QDateTime(QDate(2007, 01, 05), QTime(12, 01))); - - return model; -} +const std::array MailModel::mails = { + MailHeader{ u"RE: Sports"_s, u"Petra Schmidt "_s, + QDateTime(QDate(2007, 01, 05), QTime(12, 01)) }, + MailHeader{ u"AW: Sports"_s, u"Rolf Newschweinstein "_s, + QDateTime(QDate(2007, 01, 05), QTime(12, 00)) }, + MailHeader{ u"Sports"_s, u"Linda Smith "_s, + QDateTime(QDate(2007, 01, 05), QTime(11, 33)) }, + MailHeader{ u"Re: Accounts"_s, u"Andy "_s, + QDateTime(QDate(2007, 01, 03), QTime(14, 26)) }, + MailHeader{ u"Re: Accounts"_s, u"Joe Bloggs "_s, + QDateTime(QDate(2007, 01, 03), QTime(14, 18)) }, + MailHeader{ u"Re: Expenses"_s, u"Andy "_s, + QDateTime(QDate(2007, 01, 02), QTime(16, 05)) }, + MailHeader{ u"Expenses"_s, u"Joe Bloggs "_s, + QDateTime(QDate(2006, 12, 25), QTime(11, 39)) }, + MailHeader{ u"Accounts"_s, u"pascale@nospam.com"_s, + QDateTime(QDate(2006, 12, 31), QTime(12, 50)) }, + MailHeader{ u"Radically new concept"_s, u"Grace K. "_s, + QDateTime(QDate(2006, 12, 22), QTime(9, 44)) }, + MailHeader{ u"Happy New Year!"_s, u"Grace K. "_s, + QDateTime(QDate(2006, 12, 31), QTime(17, 03)) } +}; int main(int argc, char *argv[]) { QApplication app(argc, argv); Window window; - window.setSourceModel(createMailModel(&window)); + window.setSourceModel(new MailModel(&window)); window.show(); - return app.exec(); + return QCoreApplication::exec(); } diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.cpp index 3e2e3fbefa..12c5baafdc 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.cpp @@ -1,10 +1,26 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -#include - #include "window.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace Qt::StringLiterals; + static inline QColor textColor(const QPalette &palette) { return palette.color(QPalette::Active, QPalette::Text); @@ -20,40 +36,32 @@ static void setTextColor(QWidget *w, const QColor &c) } Window::Window() + : proxyModel(new QSortFilterProxyModel), + sourceView(new QTreeView), + proxyView(new QTreeView), + sortCaseSensitivityCheckBox(new QCheckBox(tr("Case sensitive sorting"))), + filterCaseSensitivityCheckBox(new QCheckBox(tr("Case sensitive filter"))), + filterPatternLineEdit(new QLineEdit), + filterSyntaxComboBox(new QComboBox), + filterColumnComboBox(new QComboBox) { - proxyModel = new QSortFilterProxyModel; - - sourceView = new QTreeView; sourceView->setRootIsDecorated(false); sourceView->setAlternatingRowColors(true); - proxyView = new QTreeView; proxyView->setRootIsDecorated(false); proxyView->setAlternatingRowColors(true); proxyView->setModel(proxyModel); proxyView->setSortingEnabled(true); - sortCaseSensitivityCheckBox = new QCheckBox(tr("Case sensitive sorting")); - filterCaseSensitivityCheckBox = new QCheckBox(tr("Case sensitive filter")); - - filterPatternLineEdit = new QLineEdit; filterPatternLineEdit->setClearButtonEnabled(true); - filterPatternLabel = new QLabel(tr("&Filter pattern:")); - filterPatternLabel->setBuddy(filterPatternLineEdit); - filterSyntaxComboBox = new QComboBox; filterSyntaxComboBox->addItem(tr("Regular expression"), RegularExpression); filterSyntaxComboBox->addItem(tr("Wildcard"), Wildcard); filterSyntaxComboBox->addItem(tr("Fixed string"), FixedString); - filterSyntaxLabel = new QLabel(tr("Filter &syntax:")); - filterSyntaxLabel->setBuddy(filterSyntaxComboBox); - filterColumnComboBox = new QComboBox; filterColumnComboBox->addItem(tr("Subject")); filterColumnComboBox->addItem(tr("Sender")); filterColumnComboBox->addItem(tr("Date")); - filterColumnLabel = new QLabel(tr("Filter &column:")); - filterColumnLabel->setBuddy(filterColumnComboBox); connect(filterPatternLineEdit, &QLineEdit::textChanged, this, &Window::filterRegularExpressionChanged); @@ -66,39 +74,38 @@ Window::Window() connect(sortCaseSensitivityCheckBox, &QAbstractButton::toggled, this, &Window::sortChanged); - sourceGroupBox = new QGroupBox(tr("Original Model")); - proxyGroupBox = new QGroupBox(tr("Sorted/Filtered Model")); + auto *sourceGroupBox = new QGroupBox(tr("Original Model")); + auto *proxyGroupBox = new QGroupBox(tr("Sorted/Filtered Model")); - QHBoxLayout *sourceLayout = new QHBoxLayout; + auto *sourceLayout = new QHBoxLayout(sourceGroupBox); sourceLayout->addWidget(sourceView); - sourceGroupBox->setLayout(sourceLayout); - QGridLayout *proxyLayout = new QGridLayout; - proxyLayout->addWidget(proxyView, 0, 0, 1, 3); - proxyLayout->addWidget(filterPatternLabel, 1, 0); - proxyLayout->addWidget(filterPatternLineEdit, 1, 1, 1, 2); - proxyLayout->addWidget(filterSyntaxLabel, 2, 0); - proxyLayout->addWidget(filterSyntaxComboBox, 2, 1, 1, 2); - proxyLayout->addWidget(filterColumnLabel, 3, 0); - proxyLayout->addWidget(filterColumnComboBox, 3, 1, 1, 2); - proxyLayout->addWidget(filterCaseSensitivityCheckBox, 4, 0, 1, 2); - proxyLayout->addWidget(sortCaseSensitivityCheckBox, 4, 2); - proxyGroupBox->setLayout(proxyLayout); + auto *proxyLayout = new QVBoxLayout(proxyGroupBox); + proxyLayout->addWidget(proxyView); - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *filterLayout = new QFormLayout; + filterLayout->addRow(tr("&Filter pattern:"), filterPatternLineEdit); + filterLayout->addRow(tr("Filter &syntax:"), filterSyntaxComboBox); + filterLayout->addRow(tr("Filter &column:"), filterColumnComboBox); + proxyLayout->addLayout(filterLayout); + auto *checkBoxLayout = new QHBoxLayout(); + checkBoxLayout->addWidget(filterCaseSensitivityCheckBox); + checkBoxLayout->addWidget(sortCaseSensitivityCheckBox); + checkBoxLayout->addStretch(); + proxyLayout->addLayout(checkBoxLayout); + auto *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(sourceGroupBox); mainLayout->addWidget(proxyGroupBox); - setLayout(mainLayout); - setWindowTitle(tr("Basic Sort/Filter Model")); - resize(500, 450); + auto screenGeometry = screen()->geometry(); + resize(screenGeometry.width() / 2, screenGeometry.height() * 2 / 3); proxyView->sortByColumn(1, Qt::AscendingOrder); filterColumnComboBox->setCurrentIndex(1); - filterPatternLineEdit->setText("Andy|Grace"); + filterPatternLineEdit->setText(u"Andy|Grace"_s); filterCaseSensitivityCheckBox->setChecked(true); sortCaseSensitivityCheckBox->setChecked(true); } @@ -107,6 +114,11 @@ void Window::setSourceModel(QAbstractItemModel *model) { proxyModel->setSourceModel(model); sourceView->setModel(model); + + for (int i = 0; i < proxyModel->columnCount(); ++i) + proxyView->resizeColumnToContents(i); + for (int i = 0; i < model->columnCount(); ++i) + sourceView->resizeColumnToContents(i); } void Window::filterRegularExpressionChanged() diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.h index 1ff060d9ad..7a5ebb8a2a 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/basicsortfiltermodel/window.h @@ -4,14 +4,12 @@ #ifndef WINDOW_H #define WINDOW_H -#include +#include QT_BEGIN_NAMESPACE class QAbstractItemModel; class QCheckBox; class QComboBox; -class QGroupBox; -class QLabel; class QLineEdit; class QSortFilterProxyModel; class QTreeView; @@ -34,15 +32,10 @@ private slots: private: QSortFilterProxyModel *proxyModel; - QGroupBox *sourceGroupBox; - QGroupBox *proxyGroupBox; QTreeView *sourceView; QTreeView *proxyView; - QCheckBox *filterCaseSensitivityCheckBox; QCheckBox *sortCaseSensitivityCheckBox; - QLabel *filterPatternLabel; - QLabel *filterSyntaxLabel; - QLabel *filterColumnLabel; + QCheckBox *filterCaseSensitivityCheckBox; QLineEdit *filterPatternLineEdit; enum Syntax { RegularExpression, diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/CMakeLists.txt b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/CMakeLists.txt index f95031b260..7d828e5f03 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/CMakeLists.txt @@ -11,6 +11,7 @@ qt_standard_project_setup() qt_add_executable(combowidgetmapper main.cpp window.cpp window.h + person.h ) set_target_properties(combowidgetmapper PROPERTIES diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/combowidgetmapper.pro b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/combowidgetmapper.pro index a5bbc2abe0..8bccd9cf0b 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/combowidgetmapper.pro +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/combowidgetmapper.pro @@ -1,7 +1,7 @@ QT += widgets requires(qtConfig(combobox)) -HEADERS = window.h +HEADERS = window.h person.h SOURCES = main.cpp \ window.cpp diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/main.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/main.cpp index 9c9f589816..6fd756ee9e 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/main.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/main.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -#include +#include #include "window.h" @@ -10,5 +10,5 @@ int main(int argc, char **argv) QApplication app(argc, argv); Window window; window.show(); - return app.exec(); + return QCoreApplication::exec(); } diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.cpp index fc45b8b639..cc3446988f 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.cpp @@ -1,33 +1,46 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -#include #include "window.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace Qt::StringLiterals; + //! [Set up widgets] Window::Window(QWidget *parent) - : QWidget(parent) -{ - setupModel(); - - nameLabel = new QLabel(tr("Na&me:")); - nameEdit = new QLineEdit(); - addressLabel = new QLabel(tr("&Address:")); - addressEdit = new QTextEdit(); - typeLabel = new QLabel(tr("&Type:")); - typeComboBox = new QComboBox(); - nextButton = new QPushButton(tr("&Next")); - previousButton = new QPushButton(tr("&Previous")); - - nameLabel->setBuddy(nameEdit); - addressLabel->setBuddy(addressEdit); - typeLabel->setBuddy(typeComboBox); - - typeComboBox->setModel(typeModel); + : QWidget(parent), + nameEdit(new QLineEdit), + addressEdit(new QTextEdit), + typeComboBox(new QComboBox), + nextButton(new QPushButton(tr("&Next"))), + previousButton(new QPushButton(tr("&Previous"))), //! [Set up widgets] +//! [Set up the model] + data{Person{u"Alice"_s, u"123 Main Street
Market Town
"_s, u"0"_s}, + Person{u"Bob"_s, u"PO Box 32
Mail Handling Service
Service City
"_s, u"1"_s}, + Person{u"Carol"_s, u"The Lighthouse
Remote Island
"_s, u"2"_s}, + Person{u"Donald"_s, u"47338 Park Avenue
Big City
"_s, u"0"_s}, + Person{u"Emma"_s, u"Research Station
Base Camp
Big Mountain
"_s, u"2"_s}}, + model(new QRangeModel(data, this)), + mapper(new QDataWidgetMapper(this)) +//! [Set up the model] +{ +//! [Set up type combo box] + typeComboBox->setModel(new QStringListModel({ tr("Home"), tr("Work"), tr("Other") }, this)); +//! [Set up type combo box] //! [Set up the mapper] - mapper = new QDataWidgetMapper(this); mapper->setModel(model); mapper->addMapping(nameEdit, 0); mapper->addMapping(addressEdit, 1); @@ -42,54 +55,25 @@ Window::Window(QWidget *parent) connect(mapper, &QDataWidgetMapper::currentIndexChanged, this, &Window::updateButtons); - QGridLayout *layout = new QGridLayout(); - layout->addWidget(nameLabel, 0, 0, 1, 1); - layout->addWidget(nameEdit, 0, 1, 1, 1); - layout->addWidget(previousButton, 0, 2, 1, 1); - layout->addWidget(addressLabel, 1, 0, 1, 1); - layout->addWidget(addressEdit, 1, 1, 2, 1); - layout->addWidget(nextButton, 1, 2, 1, 1); - layout->addWidget(typeLabel, 3, 0, 1, 1); - layout->addWidget(typeComboBox, 3, 1, 1, 1); - setLayout(layout); + auto *formLayout = new QFormLayout; + formLayout->addRow(tr("Na&me:"), nameEdit); + formLayout->addRow(tr("&Address:"), addressEdit); + formLayout->addRow(tr("&Type:"), typeComboBox); + + auto *buttonLayout = new QVBoxLayout; + buttonLayout->addWidget(previousButton); + buttonLayout->addWidget(nextButton); + buttonLayout->addStretch(); + + auto *mainLayout = new QHBoxLayout(this); + mainLayout->addLayout(formLayout); + mainLayout->addLayout(buttonLayout); setWindowTitle(tr("Delegate Widget Mapper")); mapper->toFirst(); } //! [Set up connections and layouts] -//! [Set up the model] -void Window::setupModel() -{ - QStringList items; - items << tr("Home") << tr("Work") << tr("Other"); - typeModel = new QStringListModel(items, this); - - model = new QStandardItemModel(5, 3, this); - QStringList names; - names << "Alice" << "Bob" << "Carol" << "Donald" << "Emma"; - QStringList addresses; - addresses << "123 Main Street
Market Town
" - << "PO Box 32
Mail Handling Service" - "
Service City
" - << "The Lighthouse
Remote Island
" - << "47338 Park Avenue
Big City
" - << "Research Station
Base Camp
Big Mountain
"; - - QStringList types; - types << "0" << "1" << "2" << "0" << "2"; - - for (int row = 0; row < 5; ++row) { - QStandardItem *item = new QStandardItem(names[row]); - model->setItem(row, 0, item); - item = new QStandardItem(addresses[row]); - model->setItem(row, 1, item); - item = new QStandardItem(types[row]); - model->setItem(row, 2, item); - } -} -//! [Set up the model] - //! [Slot for updating the buttons] void Window::updateButtons(int row) { diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.h index 9f91808021..4303daacb3 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/combowidgetmapper/window.h @@ -4,16 +4,17 @@ #ifndef WINDOW_H #define WINDOW_H -#include +#include "person.h" + +#include +#include QT_BEGIN_NAMESPACE class QComboBox; class QDataWidgetMapper; -class QLabel; class QLineEdit; class QPushButton; -class QStandardItemModel; -class QStringListModel; +class QRangeModel; class QTextEdit; QT_END_NAMESPACE @@ -29,19 +30,13 @@ private slots: void updateButtons(int row); private: - void setupModel(); - - QLabel *nameLabel; - QLabel *addressLabel; - QLabel *typeLabel; QLineEdit *nameEdit; QTextEdit *addressEdit; QComboBox *typeComboBox; QPushButton *nextButton; QPushButton *previousButton; - - QStandardItemModel *model; - QStringListModel *typeModel; + QList data; + QRangeModel *model; QDataWidgetMapper *mapper; }; //! [Window definition] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/CMakeLists.txt b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/CMakeLists.txt index a1b2c41cf6..7bcf8675d3 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/CMakeLists.txt @@ -10,7 +10,7 @@ qt_standard_project_setup() qt_add_executable(customsortfiltermodel filterwidget.cpp filterwidget.h - main.cpp + main.cpp mailheader.h mysortfilterproxymodel.cpp mysortfilterproxymodel.h window.cpp window.h ) diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/customsortfiltermodel.pro b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/customsortfiltermodel.pro index 60fd94103d..54e076dd1c 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/customsortfiltermodel.pro +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/customsortfiltermodel.pro @@ -3,7 +3,8 @@ requires(qtConfig(treeview)) HEADERS = mysortfilterproxymodel.h \ window.h \ - filterwidget.h + filterwidget.h \ + mailheader.h SOURCES = main.cpp \ mysortfilterproxymodel.cpp \ window.cpp \ diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.cpp index 69c15d25da..6804cead39 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.cpp @@ -3,13 +3,15 @@ #include "filterwidget.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include +#include + +using namespace Qt::StringLiterals; FilterWidget::FilterWidget(QWidget *parent) : QLineEdit(parent) @@ -18,30 +20,30 @@ FilterWidget::FilterWidget(QWidget *parent) setClearButtonEnabled(true); connect(this, &QLineEdit::textChanged, this, &FilterWidget::filterChanged); - QMenu *menu = new QMenu(this); + auto *menu = new QMenu(this); m_caseSensitivityAction = menu->addAction(tr("Case Sensitive")); m_caseSensitivityAction->setCheckable(true); connect(m_caseSensitivityAction, &QAction::toggled, this, &FilterWidget::filterChanged); menu->addSeparator(); m_patternGroup->setExclusive(true); - QAction *patternAction = menu->addAction("Regular Expression"); + QAction *patternAction = menu->addAction(tr("Regular Expression")); patternAction->setCheckable(true); patternAction->setChecked(true); patternAction->setData(QVariant(int(RegularExpression))); m_patternGroup->addAction(patternAction); - patternAction = menu->addAction("Wildcard"); + patternAction = menu->addAction(tr("Wildcard")); patternAction->setCheckable(true); patternAction->setData(QVariant(int(Wildcard))); m_patternGroup->addAction(patternAction); - patternAction = menu->addAction("Fixed String"); + patternAction = menu->addAction(tr("Fixed String")); patternAction->setData(QVariant(int(FixedString))); patternAction->setCheckable(true); m_patternGroup->addAction(patternAction); connect(m_patternGroup, &QActionGroup::triggered, this, &FilterWidget::filterChanged); - const QIcon icon = QIcon(QPixmap(":/images/find.png")); - QToolButton *optionsButton = new QToolButton; + const QIcon icon = QIcon(u":/images/find.png"_s); + auto *optionsButton = new QToolButton; #ifndef QT_NO_CURSOR optionsButton->setCursor(Qt::ArrowCursor); #endif @@ -50,7 +52,7 @@ FilterWidget::FilterWidget(QWidget *parent) optionsButton->setMenu(menu); optionsButton->setPopupMode(QToolButton::InstantPopup); - QWidgetAction *optionsAction = new QWidgetAction(this); + auto *optionsAction = new QWidgetAction(this); optionsAction->setDefaultWidget(optionsButton); addAction(optionsAction, QLineEdit::LeadingPosition); } diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.h index b0b8c615d1..7711381748 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/filterwidget.h @@ -4,7 +4,7 @@ #ifndef FILTERWIDGET_H #define FILTERWIDGET_H -#include +#include QT_BEGIN_NAMESPACE class QAction; diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/main.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/main.cpp index 4eefd404e2..5f2dbf4489 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/main.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/main.cpp @@ -1,58 +1,76 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause -#include - +#include "mailheader.h" #include "window.h" -void addMail(QAbstractItemModel *model, const QString &subject, - const QString &sender, const QDateTime &date) -{ - model->insertRow(0); - model->setData(model->index(0, 0), subject); - model->setData(model->index(0, 1), sender); - model->setData(model->index(0, 2), date); -} +#include -QAbstractItemModel *createMailModel(QObject *parent) -{ - QStandardItemModel *model = new QStandardItemModel(0, 3, parent); +#include - model->setHeaderData(0, Qt::Horizontal, QObject::tr("Subject")); - model->setHeaderData(1, Qt::Horizontal, QObject::tr("Sender")); - model->setHeaderData(2, Qt::Horizontal, QObject::tr("Date")); +#include - addMail(model, "Happy New Year!", "Grace K. ", - QDateTime(QDate(2006, 12, 31), QTime(17, 03))); - addMail(model, "Radically new concept", "Grace K. ", - QDateTime(QDate(2006, 12, 22), QTime(9, 44))); - addMail(model, "Accounts", "pascale@nospam.com", - QDateTime(QDate(2006, 12, 31), QTime(12, 50))); - addMail(model, "Expenses", "Joe Bloggs ", - QDateTime(QDate(2006, 12, 25), QTime(11, 39))); - addMail(model, "Re: Expenses", "Andy ", - QDateTime(QDate(2007, 01, 02), QTime(16, 05))); - addMail(model, "Re: Accounts", "Joe Bloggs ", - QDateTime(QDate(2007, 01, 03), QTime(14, 18))); - addMail(model, "Re: Accounts", "Andy ", - QDateTime(QDate(2007, 01, 03), QTime(14, 26))); - addMail(model, "Sports", "Linda Smith ", - QDateTime(QDate(2007, 01, 05), QTime(11, 33))); - addMail(model, "AW: Sports", "Rolf Newschweinstein ", - QDateTime(QDate(2007, 01, 05), QTime(12, 00))); - addMail(model, "RE: Sports", "Petra Schmidt ", - QDateTime(QDate(2007, 01, 05), QTime(12, 01))); - - return model; -} +using namespace Qt::StringLiterals; //! [0] +class MailModel : public QRangeModel +{ +public: + explicit MailModel(QObject *parent = nullptr) : QRangeModel(mails, parent) {} + + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override + { + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + switch (section) { + case 0: + return Window::tr("Subject"); + case 1: + return Window::tr("Sender"); + case 2: + return Window::tr("Date"); + default: + break; + } + } + return QRangeModel::headerData(section, orientation, role); + } + +private: + static const std::array mails; +}; + +const std::array MailModel::mails = { + MailHeader{ u"RE: Sports"_s, u"Petra Schmidt "_s, + QDateTime(QDate(2007, 01, 05), QTime(12, 01)) }, + MailHeader{ u"AW: Sports"_s, u"Rolf Newschweinstein "_s, + QDateTime(QDate(2007, 01, 05), QTime(12, 00)) }, + MailHeader{ u"Sports"_s, u"Linda Smith "_s, + QDateTime(QDate(2007, 01, 05), QTime(11, 33)) }, + MailHeader{ u"Re: Accounts"_s, u"Andy "_s, + QDateTime(QDate(2007, 01, 03), QTime(14, 26)) }, + MailHeader{ u"Re: Accounts"_s, u"Joe Bloggs "_s, + QDateTime(QDate(2007, 01, 03), QTime(14, 18)) }, + MailHeader{ u"Re: Expenses"_s, u"Andy "_s, + QDateTime(QDate(2007, 01, 02), QTime(16, 05)) }, + MailHeader{ u"Expenses"_s, u"Joe Bloggs "_s, + QDateTime(QDate(2006, 12, 25), QTime(11, 39)) }, + MailHeader{ u"Accounts"_s, u"pascale@nospam.com"_s, + QDateTime(QDate(2006, 12, 31), QTime(12, 50)) }, + MailHeader{ u"Radically new concept"_s, u"Grace K. "_s, + QDateTime(QDate(2006, 12, 22), QTime(9, 44)) }, + MailHeader{ u"Happy New Year!"_s, u"Grace K. "_s, + QDateTime(QDate(2006, 12, 31), QTime(17, 03)) } +}; +//! [0] + +//! [1] int main(int argc, char *argv[]) { QApplication app(argc, argv); Window window; - window.setSourceModel(createMailModel(&window)); + window.setSourceModel(new MailModel(&window)); window.show(); - return app.exec(); + return QCoreApplication::exec(); } -//! [0] +//! [1] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp index d5e0376c48..531b3556c3 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp @@ -3,7 +3,10 @@ #include "mysortfilterproxymodel.h" -#include +#include +#include + +using namespace Qt::StringLiterals; //! [0] MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent) @@ -53,26 +56,25 @@ bool MySortFilterProxyModel::lessThan(const QModelIndex &left, //! [4] //! [6] - if (leftData.userType() == QMetaType::QDateTime) { + if (leftData.userType() == QMetaType::QDateTime) return leftData.toDateTime() < rightData.toDateTime(); - } else { - static const QRegularExpression emailPattern("[\\w\\.]*@[\\w\\.]*"); - QString leftString = leftData.toString(); - if (left.column() == 1) { - const QRegularExpressionMatch match = emailPattern.match(leftString); - if (match.hasMatch()) - leftString = match.captured(0); - } - QString rightString = rightData.toString(); - if (right.column() == 1) { - const QRegularExpressionMatch match = emailPattern.match(rightString); - if (match.hasMatch()) - rightString = match.captured(0); - } + static const QRegularExpression emailPattern(u"[\\w\\.]*@[\\w\\.]*"_s); - return QString::localeAwareCompare(leftString, rightString) < 0; + QString leftString = leftData.toString(); + if (left.column() == 1) { + const QRegularExpressionMatch match = emailPattern.match(leftString); + if (match.hasMatch()) + leftString = match.captured(0); } + QString rightString = rightData.toString(); + if (right.column() == 1) { + const QRegularExpressionMatch match = emailPattern.match(rightString); + if (match.hasMatch()) + rightString = match.captured(0); + } + + return QString::localeAwareCompare(leftString, rightString) < 0; } //! [5] //! [6] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.h index 4a1c38c5ee..a06f2ba950 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/mysortfilterproxymodel.h @@ -4,8 +4,8 @@ #ifndef MYSORTFILTERPROXYMODEL_H #define MYSORTFILTERPROXYMODEL_H -#include -#include +#include +#include //! [0] class MySortFilterProxyModel : public QSortFilterProxyModel diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.cpp b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.cpp index c00db1a972..d39f60e992 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.cpp +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.cpp @@ -5,83 +5,84 @@ #include "mysortfilterproxymodel.h" #include "filterwidget.h" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include //! [0] Window::Window() + : proxyModel(new MySortFilterProxyModel(this)), +//! [0] + sourceView(new QTreeView), + proxyView(new QTreeView), + filterWidget(new FilterWidget), + fromDateEdit(new QDateEdit), + toDateEdit(new QDateEdit) { - proxyModel = new MySortFilterProxyModel(this); - //! [0] - //! [1] - sourceView = new QTreeView; sourceView->setRootIsDecorated(false); sourceView->setAlternatingRowColors(true); //! [1] - QHBoxLayout *sourceLayout = new QHBoxLayout; //! [2] + auto *sourceGroupBox = new QGroupBox(tr("Original Model")); + auto *sourceLayout = new QHBoxLayout(sourceGroupBox); sourceLayout->addWidget(sourceView); - sourceGroupBox = new QGroupBox(tr("Original Model")); - sourceGroupBox->setLayout(sourceLayout); //! [2] //! [3] - filterWidget = new FilterWidget; filterWidget->setText(tr("Grace|Sports")); - connect(filterWidget, &FilterWidget::filterChanged, this, &Window::textFilterChanged); - - filterPatternLabel = new QLabel(tr("&Filter pattern:")); - filterPatternLabel->setBuddy(filterWidget); - - fromDateEdit = new QDateEdit; fromDateEdit->setDate(QDate(1970, 01, 01)); - fromLabel = new QLabel(tr("F&rom:")); - fromLabel->setBuddy(fromDateEdit); - - toDateEdit = new QDateEdit; toDateEdit->setDate(QDate(2099, 12, 31)); - toLabel = new QLabel(tr("&To:")); - toLabel->setBuddy(toDateEdit); - + //! [3] + //! [4] + connect(filterWidget, &FilterWidget::filterChanged, + this, &Window::textFilterChanged); connect(filterWidget, &QLineEdit::textChanged, this, &Window::textFilterChanged); connect(fromDateEdit, &QDateTimeEdit::dateChanged, this, &Window::dateFilterChanged); connect(toDateEdit, &QDateTimeEdit::dateChanged, - //! [3] //! [4] this, &Window::dateFilterChanged); //! [4] //! [5] - proxyView = new QTreeView; proxyView->setRootIsDecorated(false); proxyView->setAlternatingRowColors(true); proxyView->setModel(proxyModel); proxyView->setSortingEnabled(true); proxyView->sortByColumn(1, Qt::AscendingOrder); - QGridLayout *proxyLayout = new QGridLayout; - proxyLayout->addWidget(proxyView, 0, 0, 1, 3); - proxyLayout->addWidget(filterPatternLabel, 1, 0); - proxyLayout->addWidget(filterWidget, 1, 1); - proxyLayout->addWidget(fromLabel, 3, 0); - proxyLayout->addWidget(fromDateEdit, 3, 1, 1, 2); - proxyLayout->addWidget(toLabel, 4, 0); - proxyLayout->addWidget(toDateEdit, 4, 1, 1, 2); + auto *proxyGroupBox = new QGroupBox(tr("Sorted/Filtered Model")); + auto *proxyLayout = new QVBoxLayout(proxyGroupBox); + proxyLayout->addWidget(proxyView); + auto *formLayout = new QFormLayout; + proxyLayout->addLayout(formLayout); + formLayout->addRow(tr("&Filter pattern:"), filterWidget); + formLayout->addRow(tr("F&rom:"), fromDateEdit); + formLayout->addRow(tr("&To:"), toDateEdit); - proxyGroupBox = new QGroupBox(tr("Sorted/Filtered Model")); - proxyGroupBox->setLayout(proxyLayout); //! [5] //! [6] - QVBoxLayout *mainLayout = new QVBoxLayout; + auto *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(sourceGroupBox); mainLayout->addWidget(proxyGroupBox); - setLayout(mainLayout); setWindowTitle(tr("Custom Sort/Filter Model")); - resize(500, 450); + auto screenGeometry = screen()->geometry(); + resize(screenGeometry.width() / 2, screenGeometry.height() * 2 / 3); } //! [6] diff --git a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.h b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.h index 793e219251..0136c4afa7 100644 --- a/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.h +++ b/local/recipes/qt/qtbase/source/examples/widgets/itemviews/customsortfiltermodel/window.h @@ -8,16 +8,13 @@ QT_BEGIN_NAMESPACE class QAbstractItemModel; -class QCheckBox; -class QComboBox; class QDateEdit; -class QGroupBox; -class QLabel; -class QLineEdit; class QTreeView; QT_END_NAMESPACE + class MySortFilterProxyModel; class FilterWidget; + //! [0] class Window : public QWidget { @@ -35,13 +32,8 @@ private slots: private: MySortFilterProxyModel *proxyModel; - QGroupBox *sourceGroupBox; - QGroupBox *proxyGroupBox; QTreeView *sourceView; QTreeView *proxyView; - QLabel *filterPatternLabel; - QLabel *fromLabel; - QLabel *toLabel; FilterWidget *filterWidget; QDateEdit *fromDateEdit; QDateEdit *toDateEdit; diff --git a/local/recipes/qt/qtbase/source/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc b/local/recipes/qt/qtbase/source/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc index 0b3ca2f47d..3b62083979 100644 --- a/local/recipes/qt/qtbase/source/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc +++ b/local/recipes/qt/qtbase/source/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc @@ -14,7 +14,7 @@ the files. The \l {QXmlStream Bookmarks Example} provides an alternative way to read this type of file. - \image screenshot.png + \image screenshot.png {Bookmark tree with Title and Location columns} \section1 The XbelTree Class Definition diff --git a/local/recipes/qt/qtbase/source/mkspecs/features/android/android.prf b/local/recipes/qt/qtbase/source/mkspecs/features/android/android.prf index 87fdd763e4..65b7f6fb51 100644 --- a/local/recipes/qt/qtbase/source/mkspecs/features/android/android.prf +++ b/local/recipes/qt/qtbase/source/mkspecs/features/android/android.prf @@ -36,7 +36,11 @@ build_pass|if(single_android_abi:!single_arch) { else:TARGET = lib$${TARGET}_$${QT_ARCH}.so } QMAKE_LFLAGS += -Wl,-soname,$$shell_quote($$TARGET) - + contains(ANDROID_TARGET_ARCH, "arm64-v8a|x86_64") { + qtConfig(android_16kb_pages) { + QMAKE_LFLAGS += -Wl,-z,max-page-size=16384 + } + } android_install { target.path=/libs/$$ANDROID_TARGET_ARCH/ INSTALLS *= target diff --git a/local/recipes/qt/qtbase/source/qmake/cachekeys.h b/local/recipes/qt/qtbase/source/qmake/cachekeys.h index d364912ee5..6b079b9385 100644 --- a/local/recipes/qt/qtbase/source/qmake/cachekeys.h +++ b/local/recipes/qt/qtbase/source/qmake/cachekeys.h @@ -12,6 +12,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE // ------------------------------------------------------------------------------------------------- @@ -40,7 +42,15 @@ struct FixStringCacheKey return hash; } }; -inline size_t qHash(const FixStringCacheKey &f) { return f.hashCode(); } +QT_BEGIN_INCLUDE_NAMESPACE +namespace std { +template <> struct hash +{ + size_t operator()(const QT_PREPEND_NAMESPACE(FixStringCacheKey) &key) const noexcept + { return key.hashCode(); } +}; +} // namespace std +QT_END_INCLUDE_NAMESPACE // ------------------------------------------------------------------------------------------------- struct FileInfoCacheKey @@ -78,7 +88,15 @@ struct FileInfoCacheKey || (c0 == QLatin1Char('\\') && c1 == QLatin1Char('\\'))); } }; -inline size_t qHash(const FileInfoCacheKey &f) { return f.hashCode(); } +QT_BEGIN_INCLUDE_NAMESPACE +namespace std { +template <> struct hash +{ + size_t operator()(const QT_PREPEND_NAMESPACE(FileInfoCacheKey) &key) const noexcept + { return key.hashCode(); } +}; +} // namespace std +QT_END_INCLUDE_NAMESPACE // ------------------------------------------------------------------------------------------------- template diff --git a/local/recipes/qt/qtbase/source/qmake/generators/makefile.cpp b/local/recipes/qt/qtbase/source/qmake/generators/makefile.cpp index 482ef2e269..e4cdb7eec8 100644 --- a/local/recipes/qt/qtbase/source/qmake/generators/makefile.cpp +++ b/local/recipes/qt/qtbase/source/qmake/generators/makefile.cpp @@ -2820,20 +2820,22 @@ MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll) QFileInfo MakefileGenerator::fileInfo(QString file) const { - Q_CONSTINIT static QHash *cache = nullptr; - static QFileInfo noInfo = QFileInfo(); + using HashMap = std::unordered_map; + Q_CONSTINIT static HashMap *cache = nullptr; if(!cache) { - cache = new QHash; - qmakeAddCacheClear(qmakeDeleteCacheClear >, (void**)&cache); + cache = new HashMap; + qmakeAddCacheClear(qmakeDeleteCacheClear, (void**)&cache); } FileInfoCacheKey cacheKey(file); - QFileInfo value = cache->value(cacheKey, noInfo); - if (value != noInfo) - return value; + + const auto it = cache->find(cacheKey); + + if (it != cache->end()) + return it->second; QFileInfo fi(file); if (fi.exists()) - cache->insert(cacheKey, fi); + cache->emplace(cacheKey, fi); return fi; } diff --git a/local/recipes/qt/qtbase/source/qmake/generators/makefile.h b/local/recipes/qt/qtbase/source/qmake/generators/makefile.h index 6ab4ad505d..47adf6c4a3 100644 --- a/local/recipes/qt/qtbase/source/qmake/generators/makefile.h +++ b/local/recipes/qt/qtbase/source/qmake/generators/makefile.h @@ -306,8 +306,9 @@ struct ReplaceExtraCompilerCacheKey hash = (size_t)forShell ^ qHash(var) ^ qHash(in) ^ qHash(out) /*^ qHash(pwd)*/; return hash; } + friend size_t qHash(const ReplaceExtraCompilerCacheKey &key, size_t seed = 0) noexcept + { return key.hashCode() ^ seed; } }; -inline size_t qHash(const ReplaceExtraCompilerCacheKey &f) { return f.hashCode(); } QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/qmake/library/proitems.cpp b/local/recipes/qt/qtbase/source/qmake/library/proitems.cpp index 2edd40a35c..0f3e42542d 100644 --- a/local/recipes/qt/qtbase/source/qmake/library/proitems.cpp +++ b/local/recipes/qt/qtbase/source/qmake/library/proitems.cpp @@ -92,11 +92,11 @@ size_t ProString::updatedHash() const return (m_hash = hash(m_string.constData() + m_offset, m_length)); } -size_t qHash(const ProString &str) +size_t qHash(const ProString &str, size_t seed) { if (!(str.m_hash & 0x80000000)) - return str.m_hash; - return str.updatedHash(); + return str.m_hash ^ seed; + return str.updatedHash() ^ seed; } ProKey::ProKey(const QString &str) : diff --git a/local/recipes/qt/qtbase/source/qmake/library/proitems.h b/local/recipes/qt/qtbase/source/qmake/library/proitems.h index 2de982034c..64d8d00c43 100644 --- a/local/recipes/qt/qtbase/source/qmake/library/proitems.h +++ b/local/recipes/qt/qtbase/source/qmake/library/proitems.h @@ -161,7 +161,8 @@ private: int m_file; mutable size_t m_hash; size_t updatedHash() const; - friend size_t qHash(const ProString &str); + friend size_t qHash(const ProString &str, size_t seed); + friend size_t qHash(const ProString &str) { return qHash(str, size_t{0}); } friend QString operator+(const ProString &one, const ProString &two); friend class ProKey; }; @@ -195,6 +196,9 @@ public: ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; } private: + friend size_t qHash(const ProKey &key, size_t seed = 0) noexcept + { return qHash(key.toString(), seed); } + ProKey(const ProString &other); }; Q_DECLARE_TYPEINFO(ProKey, Q_RELOCATABLE_TYPE); @@ -231,9 +235,6 @@ template <> struct QConcatenable : private QAbstractConcatenable } }; - -size_t qHash(const ProString &str); - inline QString &operator+=(QString &that, const ProString &other) { return that += other.toQStringView(); } diff --git a/local/recipes/qt/qtbase/source/qmake/library/qmakeevaluator.cpp b/local/recipes/qt/qtbase/source/qmake/library/qmakeevaluator.cpp index 0ee8cdbf11..1b0b872331 100644 --- a/local/recipes/qt/qtbase/source/qmake/library/qmakeevaluator.cpp +++ b/local/recipes/qt/qtbase/source/qmake/library/qmakeevaluator.cpp @@ -82,9 +82,9 @@ QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _ho { } -size_t qHash(const QMakeBaseKey &key) +size_t qHash(const QMakeBaseKey &key, size_t seed) noexcept { - return qHash(key.root) ^ qHash(key.stash) ^ (uint)key.hostBuild; + return qHashMulti(seed, key.root, key.stash, uint{key.hostBuild}); } bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two) diff --git a/local/recipes/qt/qtbase/source/qmake/library/qmakeglobals.h b/local/recipes/qt/qtbase/source/qmake/library/qmakeglobals.h index 437f131786..a9ba015bcc 100644 --- a/local/recipes/qt/qtbase/source/qmake/library/qmakeglobals.h +++ b/local/recipes/qt/qtbase/source/qmake/library/qmakeglobals.h @@ -35,9 +35,11 @@ public: QString root; QString stash; bool hostBuild; + + friend size_t qHash(const QMakeBaseKey &key, size_t seed) noexcept; + friend size_t qHash(const QMakeBaseKey &key) noexcept { return qHash(key, size_t{0}); } }; -size_t qHash(const QMakeBaseKey &key); bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two); class QMakeBaseEnv diff --git a/local/recipes/qt/qtbase/source/qmake/option.cpp b/local/recipes/qt/qtbase/source/qmake/option.cpp index 0e2d199232..4ef8d54ebb 100644 --- a/local/recipes/qt/qtbase/source/qmake/option.cpp +++ b/local/recipes/qt/qtbase/source/qmake/option.cpp @@ -15,6 +15,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE using namespace QMakeInternal; @@ -474,18 +476,19 @@ QString Option::fixString(QString string, uchar flags) { //const QString orig_string = string; - static QHash *cache = nullptr; + using HashMap = std::unordered_map; + Q_CONSTINIT static HashMap *cache = nullptr; if(!cache) { - cache = new QHash; - qmakeAddCacheClear(qmakeDeleteCacheClear >, (void**)&cache); + cache = new HashMap(); + qmakeAddCacheClear(qmakeDeleteCacheClear, (void**)&cache); } FixStringCacheKey cacheKey(string, flags); - QHash::const_iterator it = cache->constFind(cacheKey); + const auto it = cache->find(cacheKey); - if (it != cache->constEnd()) { + if (it != cache->end()) { //qDebug() << "Fix (cached) " << orig_string << "->" << it.value(); - return it.value(); + return it->second; } //fix the environment variables @@ -532,7 +535,7 @@ Option::fixString(QString string, uchar flags) //cache //qDebug() << "Fix" << orig_string << "->" << string; - cache->insert(cacheKey, string); + cache->emplace(cacheKey, string); return string; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp b/local/recipes/qt/qtbase/source/src/3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp index 42b0ed9a39..cdd0e790ee 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp +++ b/local/recipes/qt/qtbase/source/src/3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp @@ -141,6 +141,7 @@ especially to test compatibility with D3D12_RESOURCE_HEAP_TIER_1 on modern GPUs. #pragma GCC diagnostic ignored "-Wswitch" #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif #if defined(__clang__) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/forkfd/forkfd.h b/local/recipes/qt/qtbase/source/src/3rdparty/forkfd/forkfd.h index 9e4a5e1114..16cde67c8a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/forkfd/forkfd.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/forkfd/forkfd.h @@ -28,7 +28,6 @@ #include #include #include -#include #include // to get the POSIX flags #if _POSIX_SPAWN > 0 diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/README b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/README index 49dda2abb8..9e85fc8070 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/README +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/README @@ -1,4 +1,4 @@ -FreeType 2.14.2 +FreeType 2.14.3 =============== Homepage: https://freetype.org @@ -32,9 +32,9 @@ sites. Go to and download one of the following files. - freetype-doc-2.14.2.tar.xz - freetype-doc-2.14.2.tar.gz - ftdoc2142.zip + freetype-doc-2.14.3.tar.xz + freetype-doc-2.14.3.tar.gz + ftdoc2143.zip To view the documentation online, go to @@ -66,10 +66,13 @@ Please submit bug reports at https://gitlab.freedesktop.org/freetype/freetype/-/issues -Alternatively, you might report bugs by e-mail to -`freetype-devel@nongnu.org`. Don't forget to send a detailed -explanation of the problem -- there is nothing worse than receiving a -terse message that only says 'it doesn't work'. +This gitlab instance also supports confidential reports. + +Alternatively, but less preferable, you might report bugs by sending +an e-mail to the public mailing list `freetype-devel@nongnu.org`. +Don't forget to submit a detailed explanation of the problem -- there +is nothing worse than receiving a terse message that only says 'it +doesn't work'. Patches @@ -94,7 +97,7 @@ Enjoy! ---------------------------------------------------------------------- -Copyright (C) 2006-2025 by +Copyright (C) 2006-2026 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/REUSE.toml b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/REUSE.toml index 5e7c2d598c..1064d109bb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/REUSE.toml +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/REUSE.toml @@ -482,14 +482,14 @@ SPDX-License-Identifier = "FTL OR GPL-2.0-only" path = ["src/autofit/afgsub.*"] comment = "Copyright continuation line ignored by reuse for lack of word Copyright at start." precedence = "override" -SPDX-FileCopyrightText = ["Copyright (C) 2025 by David Turner, Robert Wilhelm, and Werner Lemberg."] +SPDX-FileCopyrightText = ["Copyright (C) 2026 by David Turner, Robert Wilhelm, and Werner Lemberg."] SPDX-License-Identifier = "FTL OR GPL-2.0-only" [[annotations]] path = ["src/autofit/afadjust.*"] comment = "Copyright continuation line ignored by reuse for lack of word Copyright at start." precedence = "override" -SPDX-FileCopyrightText = ["Copyright (C) 2023-2025 by David Turner, Robert Wilhelm, and Werner Lemberg and Craig White"] +SPDX-FileCopyrightText = ["Copyright (C) 2023-2026 by David Turner, Robert Wilhelm, and Werner Lemberg and Craig White"] SPDX-License-Identifier = "FTL OR GPL-2.0-only" diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/unix/ftsystem.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/unix/ftsystem.c index c0c7eebc47..84b4f39246 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/unix/ftsystem.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/unix/ftsystem.c @@ -4,7 +4,7 @@ * * Unix-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/windows/ftdebug.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/windows/ftdebug.c index dc9436436f..96bb0688a1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/windows/ftdebug.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/builds/windows/ftdebug.c @@ -4,7 +4,7 @@ * * Debugging and logging component for Win32 (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CHANGES b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CHANGES index ede0bd3e0a..0fa1e7a445 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CHANGES +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CHANGES @@ -1,3 +1,20 @@ +CHANGES BETWEEN 2.14.2 and 2.14.3 (2026-Mar-22) + + I. IMPORTANT BUG FIXES + + - A bunch of potential security problems have been found. All users + should update. + + + II. MISCELLANEOUS + + - If configuration option `TT_CONFIG_OPTION_GPOS_KERNING` is active, + GPOS-based kerning could miss some value pairs (bug introduced in + version 2.14.0). + + +====================================================================== + CHANGES BETWEEN 2.14.1 and 2.14.2 (2026-Mar-01) I. IMPORTANT CHANGES @@ -5867,7 +5884,7 @@ Extensions support: ------------------------------------------------------------------------ -Copyright (C) 2000-2025 by +Copyright (C) 2000-2026 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CUSTOMIZE b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CUSTOMIZE index 291f95eb65..890c8abdd2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CUSTOMIZE +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/CUSTOMIZE @@ -139,7 +139,7 @@ IV. Overriding default configuration and module headers ---------------------------------------------------------------------- -Copyright (C) 2003-2025 by +Copyright (C) 2003-2026 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/DEBUG b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/DEBUG index 8a997e3aaf..408b52fbc2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/DEBUG +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/DEBUG @@ -297,7 +297,7 @@ to access them. ------------------------------------------------------------------------ -Copyright (C) 2002-2025 by +Copyright (C) 2002-2026 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/TODO b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/TODO index 0c346c65b3..7c7987d1dc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/TODO +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/docs/TODO @@ -27,7 +27,7 @@ Other bugs have been registered at the savannah bugzilla of FreeType. ------------------------------------------------------------------------ -Copyright (C) 2001-2025 by +Copyright (C) 2001-2026 by David Turner, Robert Wilhelm, and Werner Lemberg. This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/qt_attribution.json b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/qt_attribution.json index 6cdd2e1c66..427ecb1f7d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/qt_attribution.json +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/qt_attribution.json @@ -8,8 +8,8 @@ "Description": "FreeType is a freely available software library to render fonts.", "Homepage": "http://www.freetype.org", - "Version": "2.14.2", - "DownloadLocation": "https://download.savannah.gnu.org/releases/freetype/freetype-2.14.2.tar.gz", + "Version": "2.14.3", + "DownloadLocation": "https://download.savannah.gnu.org/releases/freetype/freetype-2.14.3.tar.gz", "PURL": [ "pkg:github/freetype/freetype@VER-$" ], @@ -21,34 +21,34 @@ "LicenseId": "FTL OR GPL-2.0-only", "LicenseFile": "LICENSE.txt", "Copyright": ["Copyright (c) 2007-2014 Adobe Systems Incorporated", - "Copyright (c) 2004-2025 Albert Chin-A-Young", - "Copyright (c) 2018-2025 Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2004-2026 Albert Chin-A-Young", + "Copyright (c) 2018-2026 Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg", "Copyright (c) 2000 Computing Research Labs, New Mexico State University", - "Copyright (c) 1996-2025 David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg", - "Copyright (c) 2004-2025 David Turner, Robert Wilhelm, Werner Lemberg and George Williams", - "Copyright (c) 2022-2025 David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti", - "Copyright (c) 2008-2025 David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya", - "Copyright (c) 2003-2025 David Turner, Robert Wilhelm, and Werner Lemberg", - "Copyright (c) 2005-2025 David Turner", - "Copyright (c) 2007-2025 Derek Clegg and Michael Toftdal", + "Copyright (c) 1996-2026 David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg", + "Copyright (c) 2004-2026 David Turner, Robert Wilhelm, Werner Lemberg and George Williams", + "Copyright (c) 2022-2026 David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti", + "Copyright (c) 2008-2026 David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya", + "Copyright (c) 2003-2026 David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2005-2026 David Turner", + "Copyright (c) 2007-2026 Derek Clegg and Michael Toftdal", "Copyright (c) 2007 Dmitry Timoshkov for Codeweavers", "Copyright (c) 2001-2015 Francesco Zappa Nardelli", "Copyright (c) 2005, 2007, 2008, 2013 George Williams", - "Copyright (c) 2013-2025 Google, Inc. Google Author(s) Behdad Esfahbod and Stuart Gill", + "Copyright (c) 2013-2026 Google, Inc. Google Author(s) Behdad Esfahbod and Stuart Gill", "Copyright (c) 2013-2022 Google, Inc.", "Copyright (c) 2003 Huw D M Davies for Codeweavers", - "Copyright (c) 2010-2025 Joel Klinghed", - "Copyright (c) 1996-2025 Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg", - "Copyright (c) 2003-2025 Masatake YAMATO and Redhat K.K.", - "Copyright (c) 2004-2025 Masatake YAMATO, Redhat K.K, David Turner, Robert Wilhelm, and Werner Lemberg", - "Copyright (c) 2019-2025 Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg", - "Copyright (c) 2009-2025 Oran Agra and Mickey Gabel", - "Copyright (c) 2007-2025 Rahul Bhalerao ", - "Copyright (c) 2002-2025 Roberto Alameda", - "Copyright (c) 2015-2025 Werner Lemberg", - "Copyright (c) 2004-2025 suzuki toshiya, Masatake YAMATO, Red Hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2010-2026 Joel Klinghed", + "Copyright (c) 1996-2026 Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2003-2026 Masatake YAMATO and Redhat K.K.", + "Copyright (c) 2004-2026 Masatake YAMATO, Redhat K.K, David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2019-2026 Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg", + "Copyright (c) 2009-2026 Oran Agra and Mickey Gabel", + "Copyright (c) 2007-2026 Rahul Bhalerao ", + "Copyright (c) 2002-2026 Roberto Alameda", + "Copyright (c) 2015-2026 Werner Lemberg", + "Copyright (c) 2004-2026 suzuki toshiya, Masatake YAMATO, Red Hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg", "Copyright (c) 2019 nyorain", - "Copyright (c) 2022-2025 David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and Dominik Röttsches", + "Copyright (c) 2022-2026 David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and Dominik Röttsches", "Copyright (C) 2009, 2023 Red Hat, Inc."] }, { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.c index a1aa45914d..6940baf68c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to adjust components based on charcode (body). * - * Copyright (C) 2023-2025 by + * Copyright (C) 2023-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Craig White . diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.h index 4837451ae4..85dbfaad29 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afadjust.h @@ -4,7 +4,7 @@ * * Auto-fitter routines to adjust components based on charcode (header). * - * Copyright (C) 2023-2025 by + * Copyright (C) 2023-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Craig White . diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.c index a6219bdfe4..77c8389ec7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.c @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.cin b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.cin index 786c6b3b9e..70b7e02521 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.cin +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.cin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (body). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.dat b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.dat index f6e96ff818..e62754fc7e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.dat +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.dat @@ -2,7 +2,7 @@ // // Auto-fitter data for blue strings. // -// Copyright (C) 2013-2025 by +// Copyright (C) 2013-2026 by // David Turner, Robert Wilhelm, and Werner Lemberg. // // This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.h index 5bb8406dc2..f124eedee4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.h @@ -7,7 +7,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.hin b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.hin index dbac14548d..931c501060 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.hin +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afblue.hin @@ -4,7 +4,7 @@ * * Auto-fitter data for blue strings (specification). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.c index 7086601838..7a1cc32c9d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (body). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.h index bd1b39358e..98681868a8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcjk.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for CJK writing system (specification). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcover.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcover.h index b93bcd1a2c..d60e0050be 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcover.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afcover.h @@ -4,7 +4,7 @@ * * Auto-fitter coverages (specification only). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.c index 8613544f91..f9d1dd38db 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.c @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.h index 78a79439d9..14546b1e50 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afdummy.h @@ -5,7 +5,7 @@ * Auto-fitter dummy routines to be used if no hinting should be * performed (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aferrors.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aferrors.h index f3093fc90d..3d7538ba2d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aferrors.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aferrors.h @@ -4,7 +4,7 @@ * * Autofitter error codes (specification only). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.c index e74d814116..ff6903cc17 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to compute global hinting values (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.h index dc06115949..c4dd933583 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afglobal.h @@ -5,7 +5,7 @@ * Auto-fitter routines to compute global hinting values * (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.c index 2adf809dd5..af7b0f6798 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.c @@ -4,7 +4,7 @@ * * Auto-fitter routines to parse the GSUB table (body). * - * Copyright (C) 2025 by + * Copyright (C) 2025-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.h index d57d61475b..10884f9236 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afgsub.h @@ -4,7 +4,7 @@ * * Auto-fitter routines to parse the GSUB table (header). * - * Copyright (C) 2025 by + * Copyright (C) 2025-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.c index 11faa655f6..376912a5d1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.h index 46b3ed3366..84244d6f5c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afhints.h @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.c index a2cd14f881..29b6d22ed6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for Indic writing system (body). * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.h index a2e825e9f8..df4892a9f1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afindic.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for Indic writing system * (specification). * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * Rahul Bhalerao , . * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.c index 4a42d91947..73addf28eb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.c @@ -4,7 +4,7 @@ * * Auto-fitter hinting routines for latin writing system (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.h index 82b4b0d480..b6bdc5177f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aflatin.h @@ -5,7 +5,7 @@ * Auto-fitter hinting routines for latin writing system * (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.c index 4e2ac1f1ce..8ac7b53856 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.c @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.h index a04b4df0b3..8efd0fd57e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afloader.h @@ -4,7 +4,7 @@ * * Auto-fitter glyph loading routines (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.c index 22d85a889e..57d5d47dfb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.c @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.h index c62421ef69..1f8a68122d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afmodule.h @@ -4,7 +4,7 @@ * * Auto-fitter module implementation (specification). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.c index fd54948f3a..4d0755decb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.c @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (body). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.h index fa00eb7504..f293694512 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afranges.h @@ -4,7 +4,7 @@ * * Auto-fitter Unicode script ranges (specification). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afscript.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afscript.h index 5c4cbbcb92..d071ed68b7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afscript.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afscript.h @@ -4,7 +4,7 @@ * * Auto-fitter scripts (specification only). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.c index f3c0744fd9..5c9e5376ad 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.c @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (body). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.h index 757368fc9c..6e73b9fb2e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afshaper.h @@ -4,7 +4,7 @@ * * HarfBuzz interface for accessing OpenType features (specification). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afstyles.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afstyles.h index 206232efe2..e7a7fe531b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afstyles.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afstyles.h @@ -4,7 +4,7 @@ * * Auto-fitter styles (specification only). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aftypes.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aftypes.h index 959640a12e..a3a881eede 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aftypes.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/aftypes.h @@ -4,7 +4,7 @@ * * Auto-fitter types (specification only). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-decl.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-decl.h index 12fa7a27a2..ddebdcd1e7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-decl.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-decl.h @@ -4,7 +4,7 @@ * * Auto-fitter writing system declarations (specification only). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-iter.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-iter.h index 1752697b37..720c2dc50c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-iter.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/afws-iter.h @@ -4,7 +4,7 @@ * * Auto-fitter writing systems iterator (specification only). * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/autofit.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/autofit.c index f3fb1974d1..8cd973bf14 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/autofit.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/autofit.c @@ -4,7 +4,7 @@ * * Auto-fitter module (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.c index 3c145d0464..ed438da6af 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.c @@ -4,7 +4,7 @@ * * FreeType-HarfBuzz bridge (body). * - * Copyright (C) 2025 by + * Copyright (C) 2025-2026 by * Behdad Esfahbod. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.h index 95914deb8d..d2cc0482eb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/ft-hb.h @@ -4,7 +4,7 @@ * * FreeType-HarfBuzz bridge (specification). * - * Copyright (C) 2025 by + * Copyright (C) 2025-2026 by * Behdad Esfahbod. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/module.mk index c4515c5d48..a82bedb9f2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2003-2025 by +# Copyright (C) 2003-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/rules.mk index 03fb5a5edf..9e39db33c9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/autofit/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2003-2025 by +# Copyright (C) 2003-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftadvanc.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftadvanc.c index 7b965c62d5..6485834666 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftadvanc.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftadvanc.c @@ -4,7 +4,7 @@ * * Quick computation of advance widths (body). * - * Copyright (C) 2008-2025 by + * Copyright (C) 2008-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.c index 72bae31fdc..5a5c851598 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.c @@ -4,7 +4,7 @@ * * Single object library component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.h index 66f091165f..952ac51d50 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbase.h @@ -4,7 +4,7 @@ * * Private functions used in the `base' module (specification). * - * Copyright (C) 2008-2025 by + * Copyright (C) 2008-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbbox.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbbox.c index feccdee5dd..4641ce27e8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbbox.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbbox.c @@ -4,7 +4,7 @@ * * FreeType bbox computation (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbdf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbdf.c index f15da313d8..7ce76d3c48 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbdf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbdf.c @@ -4,7 +4,7 @@ * * FreeType API for accessing BDF-specific strings (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbitmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbitmap.c index 364f881e43..f88cbc11e6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbitmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftbitmap.c @@ -4,7 +4,7 @@ * * FreeType utility functions for bitmaps (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcalc.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcalc.c index 7d6e12e254..d233dba3d6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcalc.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcalc.c @@ -4,7 +4,7 @@ * * Arithmetic computations (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcid.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcid.c index 35cd0fcd2b..878c666e12 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcid.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcid.c @@ -4,7 +4,7 @@ * * FreeType API for accessing CID font information. * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * Derek Clegg and Michael Toftdal. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcolor.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcolor.c index 90b02b7d2d..ed6b5f0599 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcolor.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftcolor.c @@ -4,7 +4,7 @@ * * FreeType's glyph color management (body). * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdbgmem.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdbgmem.c index 7f54e759b1..0335f14256 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdbgmem.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdbgmem.c @@ -4,7 +4,7 @@ * * Memory debugger (body). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdebug.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdebug.c index c615f29e52..27091a5579 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdebug.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftdebug.c @@ -4,7 +4,7 @@ * * Debugging and logging component (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fterrors.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fterrors.c index 27e9c5134e..a140dab860 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fterrors.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fterrors.c @@ -4,7 +4,7 @@ * * FreeType API for error code handling. * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfntfmt.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfntfmt.c index 7f4f14ffdb..99e8c2b17d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfntfmt.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfntfmt.c @@ -4,7 +4,7 @@ * * FreeType utility file for font formats (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfstype.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfstype.c index 3a95752ffa..58d5144a9e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfstype.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftfstype.c @@ -4,7 +4,7 @@ * * FreeType utility file to access FSType data (body). * - * Copyright (C) 2008-2025 by + * Copyright (C) 2008-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgasp.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgasp.c index 2202240b57..3c13456802 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgasp.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgasp.c @@ -4,7 +4,7 @@ * * Access of TrueType's `gasp' table (body). * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgloadr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgloadr.c index 47781bc4d5..bd66e61d1c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgloadr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgloadr.c @@ -4,7 +4,7 @@ * * The FreeType glyph loader (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftglyph.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftglyph.c index 6138cfeec2..096f4d965e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftglyph.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftglyph.c @@ -4,7 +4,7 @@ * * FreeType convenience functions to handle glyphs (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -856,9 +856,9 @@ goto Exit; /* in case of success, copy the bitmap to the glyph bitmap */ - error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy ); - if ( error ) - goto Exit; + bitmap->left = dummy.bitmap_left; + bitmap->top = dummy.bitmap_top; + bitmap->bitmap = dummy.bitmap; /* copy advance */ bitmap->root.advance = glyph->advance; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgxval.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgxval.c index 1961cf4fbe..e48f582c71 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgxval.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftgxval.c @@ -4,7 +4,7 @@ * * FreeType API for validating TrueTypeGX/AAT tables (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * Masatake YAMATO, Redhat K.K, * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftinit.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftinit.c index 37d7f87bcb..b20289316d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftinit.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftinit.c @@ -4,7 +4,7 @@ * * FreeType initialization layer (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftlcdfil.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftlcdfil.c index 51c6fd48a1..9adbf7518f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftlcdfil.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftlcdfil.c @@ -4,7 +4,7 @@ * * FreeType API for color filtering of subpixel bitmap glyphs (body). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmac.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmac.c index 37d97be183..7251a4cb96 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmac.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmac.c @@ -8,7 +8,7 @@ * This file is for Mac OS X only; see builds/mac/ftoldmac.c for * classic platforms built by MPW. * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmm.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmm.c index 9e67001406..0d3bf3b77d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmm.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftmm.c @@ -4,7 +4,7 @@ * * Multiple Master font support (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftobjs.c index 323dd5efac..f9f64c40fe 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftobjs.c @@ -4,7 +4,7 @@ * * The FreeType private base classes (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -385,6 +385,7 @@ FT_Pos y_shift = 0; FT_Pos x_left, y_top; FT_Pos width, height, pitch; + FT_Bool ret; if ( slot->format == FT_GLYPH_FORMAT_SVG ) @@ -495,6 +496,20 @@ width = pbox.xMax - pbox.xMin; height = pbox.yMax - pbox.yMin; + /* Flag the width or height unsuitable for rendering. */ + /* The limit is based on the ppem value when available. */ + /* FT_Renderer modules should check the return value. */ + ret = FT_BOOL( width >= 0x10000 || height >= 0x10000 || + pbox.xMin < -0x1000000 || pbox.xMax >= 0x1000000 || + pbox.yMin < -0x1000000 || pbox.yMax >= 0x1000000 || + ( slot->face && + ( width > 10 * slot->face->size->metrics.x_ppem || + height > 10 * slot->face->size->metrics.y_ppem ) ) ); + + if ( ret ) + FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n", + pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax )); + switch ( pixel_mode ) { case FT_PIXEL_MODE_MONO: @@ -524,31 +539,7 @@ bitmap->rows = (unsigned int)height; bitmap->pitch = pitch; - /* Flag the bounding box size unsuitable for rendering. */ - /* FT_Renderer modules should check the return value. */ - /* The limit is based on the ppem value when available. */ - { - FT_Face face = slot->face; - FT_Pos xlim = 0x8000; - FT_Pos ylim = 0x8000; - - - if ( face ) - { - xlim = FT_MIN( xlim, 10 * face->size->metrics.x_ppem ); - ylim = FT_MIN( ylim, 10 * face->size->metrics.y_ppem ); - } - - if ( pbox.xMin < -xlim || pbox.xMax >= xlim || - pbox.yMin < -ylim || pbox.yMax >= ylim ) - { - FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n", - pbox.xMin, pbox.yMin, pbox.xMax, pbox.yMax )); - return 1; - } - } - - return 0; + return ret; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftotval.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftotval.c index 503126f4b6..ae14113612 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftotval.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftotval.c @@ -4,7 +4,7 @@ * * FreeType API for validating OpenType tables (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftoutln.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftoutln.c index 8a15b03eb8..a0a1549ada 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftoutln.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftoutln.c @@ -4,7 +4,7 @@ * * FreeType outline management (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpatent.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpatent.c index 664bc34dee..3f149eb607 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpatent.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpatent.c @@ -5,7 +5,7 @@ * FreeType API for checking patented TrueType bytecode instructions * (body). Obsolete, retained for backward compatibility. * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpfr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpfr.c index f2af1fecc2..f95808201a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpfr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpfr.c @@ -4,7 +4,7 @@ * * FreeType API for accessing PFR-specific data (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpsprop.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpsprop.c index 0631cd63f6..13f6c5102c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpsprop.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftpsprop.c @@ -5,7 +5,7 @@ * Get and set properties of PostScript drivers (body). * See `ftdriver.h' for available properties. * - * Copyright (C) 2017-2025 by + * Copyright (C) 2017-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftrfork.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftrfork.c index 1e241f4f95..fbb8ace717 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftrfork.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftrfork.c @@ -4,7 +4,7 @@ * * Embedded resource forks accessor (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * Masatake YAMATO and Redhat K.K. * * FT_Raccess_Get_HeaderInfo() and raccess_guess_darwin_hfsplus() are diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsnames.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsnames.c index 34a67a148f..d8274cccd4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsnames.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsnames.c @@ -7,7 +7,7 @@ * * This is _not_ used to retrieve glyph names! * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstream.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstream.c index c04a0506de..b08a1a9b65 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstream.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstream.c @@ -4,7 +4,7 @@ * * I/O stream support (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstroke.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstroke.c index 591f18eaa8..e599ecaf46 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstroke.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftstroke.c @@ -4,7 +4,7 @@ * * FreeType path stroker (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -693,6 +693,7 @@ Fail: num_points = 0; num_contours = 0; + error = FT_THROW( Invalid_Outline ); goto Exit; } @@ -2251,7 +2252,7 @@ FT_Stroker stroker, FT_Bool destroy ) { - FT_Error error = FT_ERR( Invalid_Argument ); + FT_Error error = FT_THROW( Invalid_Argument ); FT_Glyph glyph = NULL; @@ -2283,7 +2284,9 @@ if ( error ) goto Fail; - FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + error = FT_Stroker_GetCounts( stroker, &num_points, &num_contours ); + if ( error ) + goto Fail; FT_Outline_Done( glyph->library, outline ); @@ -2326,7 +2329,7 @@ FT_Bool inside, FT_Bool destroy ) { - FT_Error error = FT_ERR( Invalid_Argument ); + FT_Error error = FT_THROW( Invalid_Argument ); FT_Glyph glyph = NULL; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsynth.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsynth.c index 08bc174220..23960eda3a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsynth.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsynth.c @@ -4,7 +4,7 @@ * * FreeType synthesizing code for emboldening and slanting (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsystem.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsystem.c index 186119d558..be9159f614 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsystem.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftsystem.c @@ -4,7 +4,7 @@ * * ANSI-specific FreeType low-level system interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttrigon.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttrigon.c index 29eff639c5..baa47eba08 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttrigon.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttrigon.c @@ -4,7 +4,7 @@ * * FreeType trigonometric functions (body). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttype1.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttype1.c index 77978df674..f9a46801f3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttype1.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/fttype1.c @@ -4,7 +4,7 @@ * * FreeType utility file for PS names support (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftutil.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftutil.c index f83c439489..5d8fc7b9bf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftutil.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftutil.c @@ -4,7 +4,7 @@ * * FreeType utility file for memory and list management (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftver.rc b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftver.rc index 7f4d2c12e8..8938831d18 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftver.rc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftver.rc @@ -4,7 +4,7 @@ /* */ /* FreeType VERSIONINFO resource for Windows DLLs. */ /* */ -/* Copyright (C) 2018-2025 by */ +/* Copyright (C) 2018-2026 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -18,8 +18,8 @@ #include -#define FT_VERSION 2,14,2,0 -#define FT_VERSION_STR "2.14.2" +#define FT_VERSION 2,14,3,0 +#define FT_VERSION_STR "2.14.3" VS_VERSION_INFO VERSIONINFO FILEVERSION FT_VERSION diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftwinfnt.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftwinfnt.c index 256b58005e..038451ae09 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftwinfnt.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/ftwinfnt.c @@ -4,7 +4,7 @@ * * FreeType API for accessing Windows FNT specific info (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/rules.mk index a1a95726ad..e806066485 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/base/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/ftbzip2.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/ftbzip2.c index 16d158d72d..6326c71ac1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/ftbzip2.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/ftbzip2.c @@ -8,7 +8,7 @@ * parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2010-2025 by + * Copyright (C) 2010-2026 by * Joel Klinghed. * * based on `src/gzip/ftgzip.c' diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/rules.mk index 59fefb2276..3adf306533 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/bzip2/rules.mk @@ -2,7 +2,7 @@ # FreeType 2 BZIP2 support configuration rules # -# Copyright (C) 2010-2025 by +# Copyright (C) 2010-2026 by # Joel Klinghed. # # based on `src/lzw/rules.mk' diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcache.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcache.c index afdf1e4f5b..95f784370d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcache.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcache.c @@ -4,7 +4,7 @@ * * The FreeType Caching sub-system (body only). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcbasic.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcbasic.c index e7cf2605fe..81c5ded473 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcbasic.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcbasic.c @@ -4,7 +4,7 @@ * * The FreeType basic cache interface (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.c index 91227147a8..28f3f3e7a0 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.c @@ -4,7 +4,7 @@ * * The FreeType internal cache interface (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.h index 20c2638e72..55ecf5e70c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccache.h @@ -4,7 +4,7 @@ * * FreeType internal cache interface (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccback.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccback.h index 1af2f17f97..f013833e66 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccback.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccback.h @@ -4,7 +4,7 @@ * * Callback functions of the caching sub-system (specification only). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccmap.c index e3a4ec2429..758468fb45 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftccmap.c @@ -4,7 +4,7 @@ * * FreeType CharMap cache (body) * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcerror.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcerror.h index f714491c75..41491c2f46 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcerror.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcerror.h @@ -4,7 +4,7 @@ * * Caching sub-system error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.c index 703c69d91f..3c291ce50f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.c @@ -4,7 +4,7 @@ * * FreeType Glyph Image (FT_Glyph) cache (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.h index b728b636e4..1777a17e53 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcglyph.h @@ -4,7 +4,7 @@ * * FreeType abstract glyph cache (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.c index 05d393dcd9..b028bf8e45 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.c @@ -4,7 +4,7 @@ * * FreeType Image cache (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.h index 8eb1482624..d48c54c51b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcimage.h @@ -4,7 +4,7 @@ * * FreeType Generic Image cache (specification) * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.c index 4bfb389bb7..4c1d85ab1f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.c @@ -4,7 +4,7 @@ * * FreeType Cache Manager (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.h index c691aebb39..22d56d7eb8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmanag.h @@ -4,7 +4,7 @@ * * FreeType Cache Manager (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.c index 2a5f2f3aa5..e8dc9052da 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.c @@ -4,7 +4,7 @@ * * FreeType MRU support (body). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.h index 18e7a840ea..962d088687 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcmru.h @@ -4,7 +4,7 @@ * * Simple MRU list-cache (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.c index 6857f82b41..7f6a9b1b4e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.c @@ -4,7 +4,7 @@ * * FreeType sbits manager (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.h index 20ccb13b73..669e77cb30 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/ftcsbits.h @@ -4,7 +4,7 @@ * * A small-bitmap cache (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/rules.mk index ec7b2df507..6f56da9420 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cache/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2000-2025 by +# Copyright (C) 2000-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cff.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cff.c index 01d641ff98..8125c104d1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cff.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cff.c @@ -4,7 +4,7 @@ * * FreeType OpenType driver component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.c index cb69abdb90..75e2420d99 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.c @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.h index 60e16d9487..e812e7a89e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffcmap.h @@ -4,7 +4,7 @@ * * CFF character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.c index 44ff44aecb..18c7b87904 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.c @@ -4,7 +4,7 @@ * * OpenType font driver implementation (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Dominik Röttsches. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.h index 52a1e727a6..2f3c58b67d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffdrivr.h @@ -4,7 +4,7 @@ * * High-level OpenType driver interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfferrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfferrs.h index 7491886c7b..ca1158c0df 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfferrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfferrs.h @@ -4,7 +4,7 @@ * * CFF error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.c index e8bab3c1e3..0c986930ce 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.c @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.h index 662bb7cff5..eb4b5f30b5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.c index 39d662eb43..9d067cfeeb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.c @@ -4,7 +4,7 @@ * * OpenType and CFF data/program tables loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.h index fdc132c8f3..ab02ca2d7f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffload.h @@ -4,7 +4,7 @@ * * OpenType & CFF data/program tables loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.c index 9e00943a95..c6ba35e273 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.c @@ -4,7 +4,7 @@ * * OpenType objects manager (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -16,7 +16,6 @@ */ - #include #include #include @@ -45,6 +44,7 @@ #define CFF_fixedToInt( x ) \ ( (FT_Short)( ( (x) + 0x8000U ) >> 16 ) ) + /************************************************************************** * * The macro FT_COMPONENT is used in trace mode. It is an implicit diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.h index 982dcd64dd..c6ab805c5b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffobjs.h @@ -4,7 +4,7 @@ * * OpenType objects manager (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -20,8 +20,6 @@ #define CFFOBJS_H_ - - FT_BEGIN_HEADER diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.c index 864b2490b3..fadc3258c9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.c @@ -4,7 +4,7 @@ * * CFF token stream parser (body) * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.h index 47cceb1a4a..1daf548cbc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cffparse.h @@ -4,7 +4,7 @@ * * CFF token stream parser (specification) * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfftoken.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfftoken.h index a7ee1cb3fe..0eadc7118f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfftoken.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/cfftoken.h @@ -4,7 +4,7 @@ * * CFF token definitions (specification only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/module.mk index e02e501940..14dda50d66 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/rules.mk index f2b7ce45b4..f3a729db5d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cff/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/ciderrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/ciderrs.h index 1591979d37..00497b796b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/ciderrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/ciderrs.h @@ -4,7 +4,7 @@ * * CID error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.c index 249ede5757..cc68b4a960 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 Glyph Loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -193,6 +193,37 @@ p = (FT_Byte*)glyph_data.pointer; fd_select = cid_get_offset( &p, cid->fd_bytes ); + if ( fd_select >= cid->num_dicts ) + { + /* + * fd_select == 0xFF is often used to indicate that the CID + * has no charstring to be rendered, similar to GID = 0xFFFF + * in TrueType fonts. + */ + if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) || + ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) + { + FT_TRACE1(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE1(( " FD number %lu is the maximum\n", + fd_select )); + FT_TRACE1(( " integer fitting into %u byte%s\n", + cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" )); + } + else + { + FT_TRACE0(( "cid_load_glyph: fail for glyph index %u:\n", + glyph_index )); + FT_TRACE0(( " FD number %lu is larger\n", + fd_select )); + FT_TRACE0(( " than number of dictionaries (%u)\n", + cid->num_dicts )); + } + + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + glyph_length = glyph_data.length - cid->fd_bytes; if ( !FT_QALLOC( charstring, glyph_length ) ) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.h index cef96073de..51b16c7594 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidgload.h @@ -4,7 +4,7 @@ * * OpenType Glyph Loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.c index bb1bf13e22..1a0e6b1561 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.h index 659dd0e378..cef7d1c9a6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidload.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 font loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.c index 634bbf2f13..2d11609598 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.c @@ -4,7 +4,7 @@ * * CID objects manager (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.h index 800268efa2..4066462312 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidobjs.h @@ -4,7 +4,7 @@ * * CID objects manager (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.c index 4d1ba33596..fb936bd48d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.c @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.h index 6ae2e54239..555245230b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidparse.h @@ -4,7 +4,7 @@ * * CID-keyed Type1 parser (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.c index a3a587c57b..ab188776e2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.c @@ -4,7 +4,7 @@ * * CID driver interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.h index 55d0b8a0d9..a4ddccec80 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidriver.h @@ -4,7 +4,7 @@ * * High-level CID driver interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidtoken.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidtoken.h index d40ebfab86..22136310cd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidtoken.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/cidtoken.h @@ -4,7 +4,7 @@ * * CID token definitions (specification only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/module.mk index 7120b8f3c3..2994e4777c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/rules.mk index bf87ef09a6..5569c7c5eb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/type1cid.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/type1cid.c index 1291ba7a2a..fbcce4f70b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/type1cid.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/cid/type1cid.c @@ -4,7 +4,7 @@ * * FreeType OpenType driver component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/dlgwrap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/dlgwrap.c index 8bb5b0011b..159af2d675 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/dlgwrap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/dlgwrap.c @@ -4,7 +4,7 @@ * * Wrapper file for the 'dlg' library (body only) * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/rules.mk index 7aac2433d5..f575a8bd1e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/dlg/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2020-2025 by +# Copyright (C) 2020-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/README b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/README index 5eb623b3d4..1bde33300e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/README +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/README @@ -518,7 +518,7 @@ gxvalid: TrueType GX validator ------------------------------------------------------------------------ -Copyright (C) 2004-2025 by +Copyright (C) 2004-2026 by suzuki toshiya, Masatake YAMATO, Red hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.c index d3f2d12dc9..93c10f127d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.c @@ -4,7 +4,7 @@ * * FreeType validator for TrueTypeGX/AAT tables (body only). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.h index a9537a1560..ee76946147 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvalid.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT table validation (specification only). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvbsln.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvbsln.c index 28f1873b09..9b9c10b980 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvbsln.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvbsln.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT bsln table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.c index f666404440..111db5c693 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common tables validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.h index 1e19ccfb6b..cc95c4cece 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvcommn.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common tables validation (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxverror.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxverror.h index 73acb7fa41..90a6eda03e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxverror.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxverror.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT validation module error codes (specification only). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.c index 5d4aca04c6..826f3eedf5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT feat table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.h index 6a0cbea35a..9d34b701a2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfeat.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT feat table validation (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfgen.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfgen.c index 13a88826b7..d0c53ca526 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfgen.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvfgen.c @@ -5,7 +5,7 @@ * Generate feature registry data for gxv `feat' validator. * This program is derived from gxfeatreg.c in gxlayout. * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * Masatake YAMATO and Redhat K.K. * * This file may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvjust.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvjust.c index 1b3a8b1ac1..c5177522e3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvjust.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvjust.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT just table validation (body). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvkern.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvkern.c index 222fd038ca..f1f8ce7cd3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvkern.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvkern.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT kern table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvlcar.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvlcar.c index 4882df4249..7b90d43a7b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvlcar.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvlcar.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT lcar table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.c index 4f27c5a8a9..89e142be5d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.c @@ -4,7 +4,7 @@ * * FreeType's TrueTypeGX/AAT validation module implementation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.h index 39a375d978..51e339e00b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmod.h @@ -5,7 +5,7 @@ * FreeType's TrueTypeGX/AAT validation module implementation * (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.c index 846ac48b99..de03f2e388 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT mort table validation (body). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.h index 66d46a072b..3db0d2a61e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common definition for mort table (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort0.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort0.c index 5817c27d7a..78b042d5de 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort0.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort0.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type0 (Indic Script Rearrangement) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort1.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort1.c index 20cccadf17..57ee197d48 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort1.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort1.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type1 (Contextual Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort2.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort2.c index 80aabbc9c5..e982a67bf5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort2.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort2.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type2 (Ligature Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort4.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort4.c index 40ed730071..2ad0632fa5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort4.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort4.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type4 (Non-Contextual Glyph Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort5.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort5.c index 1b274be3b6..613debd453 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort5.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmort5.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT mort table validation * body for type5 (Contextual Glyph Insertion) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.c index 931e57b00c..9efe182038 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT morx table validation (body). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.h index 2b8bf3575d..60b084a8d0 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx.h @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT common definition for morx table (specification). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx0.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx0.c index 0085ac92f1..54cded1f64 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx0.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx0.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type0 (Indic Script Rearrangement) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx1.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx1.c index b495412ffc..56a64c257c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx1.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx1.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type1 (Contextual Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx2.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx2.c index 0527161dc3..be333e0424 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx2.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx2.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type2 (Ligature Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx4.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx4.c index e6e99fcb74..9af41f4bf5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx4.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx4.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for "morx" type4 (Non-Contextual Glyph Substitution) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx5.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx5.c index 7dec9a9015..edc3f3bc01 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx5.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvmorx5.c @@ -5,7 +5,7 @@ * TrueTypeGX/AAT morx table validation * body for type5 (Contextual Glyph Insertion) subtable. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvopbd.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvopbd.c index 65003100ca..265ad39a2c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvopbd.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvopbd.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT opbd table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvprop.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvprop.c index 31f2b5eb30..f27ce103c4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvprop.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvprop.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT prop table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvtrak.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvtrak.c index 329f12729d..06300beff3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvtrak.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/gxvtrak.c @@ -4,7 +4,7 @@ * * TrueTypeGX/AAT trak table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * suzuki toshiya, Masatake YAMATO, Red Hat K.K., * David Turner, Robert Wilhelm, and Werner Lemberg. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/module.mk index c222466e8b..d6b58ee922 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/module.mk @@ -2,7 +2,7 @@ # FreeType 2 gxvalid module definition # -# Copyright (C) 2004-2025 by +# Copyright (C) 2004-2026 by # suzuki toshiya, Masatake YAMATO, Red Hat K.K., # David Turner, Robert Wilhelm, and Werner Lemberg. # diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/rules.mk index 78382bef9f..552f64dcc3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gxvalid/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2004-2025 by +# Copyright (C) 2004-2026 by # suzuki toshiya, Masatake YAMATO, Red Hat K.K., # David Turner, Robert Wilhelm, and Werner Lemberg. # diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/ftgzip.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/ftgzip.c index ffa3824d44..4a5ec87297 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/ftgzip.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/ftgzip.c @@ -8,7 +8,7 @@ * parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/rules.mk index 8c1324efd3..baefc0b9ba 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/gzip/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2002-2025 by +# Copyright (C) 2002-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftlzw.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftlzw.c index 09de4a10f5..ce5070d75f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftlzw.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftlzw.c @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * Albert Chin-A-Young. * * based on code in `src/gzip/ftgzip.c' diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.c index 1dffedd03d..3a42824902 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.c @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.h index e362a5366d..9c06b367d8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/ftzopen.h @@ -8,7 +8,7 @@ * be used to parse compressed PCF fonts, as found with many X11 server * distributions. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/rules.mk index 9d29b0b60c..ec996bb918 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/lzw/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2004-2025 by +# Copyright (C) 2004-2026 by # Albert Chin-A-Young. # # based on `src/lzw/rules.mk' diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/module.mk index a025a5418b..dadc349f3a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2004-2025 by +# Copyright (C) 2004-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.c index 6ca90581ef..e68a0823fe 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.c @@ -4,7 +4,7 @@ * * FreeType validator for OpenType tables (body only). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.h index 2b5598e0cd..6ab7c65cb4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvalid.h @@ -4,7 +4,7 @@ * * OpenType table validation (specification only). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvbase.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvbase.c index cbaf4c27ce..8cea131939 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvbase.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvbase.c @@ -4,7 +4,7 @@ * * OpenType BASE table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.c index 167026c274..a6771c7826 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.c @@ -4,7 +4,7 @@ * * OpenType common tables validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.h index 20f38b495b..4648e70dee 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvcommn.h @@ -4,7 +4,7 @@ * * OpenType common tables validation (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otverror.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otverror.h index 17fb5fb840..d1c2c4b56c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otverror.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otverror.h @@ -4,7 +4,7 @@ * * OpenType validation module error codes (specification only). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgdef.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgdef.c index fa523fb325..08d0a68d68 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgdef.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgdef.c @@ -4,7 +4,7 @@ * * OpenType GDEF table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.c index 1d99c80fd1..b9e36bd833 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.c @@ -4,7 +4,7 @@ * * OpenType GPOS table validation (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.h index 2fc1309e1c..8539801fd9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgpos.h @@ -4,7 +4,7 @@ * * OpenType GPOS table validator (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgsub.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgsub.c index 0df97d8dbb..2669be37c9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgsub.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvgsub.c @@ -4,7 +4,7 @@ * * OpenType GSUB table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvjstf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvjstf.c index 8909612d9f..6706e1a7f8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvjstf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvjstf.c @@ -4,7 +4,7 @@ * * OpenType JSTF table validation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmath.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmath.c index 78e6c66926..80d78890be 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmath.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmath.c @@ -4,7 +4,7 @@ * * OpenType MATH table validation (body). * - * Copyright (C) 2007-2025 by + * Copyright (C) 2007-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by George Williams. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.c index d2456cb58f..946c81902f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.c @@ -4,7 +4,7 @@ * * FreeType's OpenType validation module implementation (body). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.h index aec6f66574..f00f98f125 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/otvmod.h @@ -5,7 +5,7 @@ * FreeType's OpenType validation module implementation * (specification). * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/rules.mk index e254649975..83c426829d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/otvalid/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2004-2025 by +# Copyright (C) 2004-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/module.mk index d08c5cfb99..9d57e36bb5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2002-2025 by +# Copyright (C) 2002-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfr.c index ecfc4f22c8..260c2703ce 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfr.c @@ -4,7 +4,7 @@ * * FreeType PFR driver component. * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.c index 489b1a5ddd..786aaa1163 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.c @@ -4,7 +4,7 @@ * * FreeType PFR cmap handling (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.h index acf4b508da..9ebb3f23da 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrcmap.h @@ -4,7 +4,7 @@ * * FreeType PFR cmap handling (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.c index 268924b506..31f3509bb7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.c @@ -4,7 +4,7 @@ * * FreeType PFR driver interface (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.h index 61aadb9738..2c75a14d78 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrdrivr.h @@ -4,7 +4,7 @@ * * High-level Type PFR driver interface (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrerror.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrerror.h index 479e3728f4..78cbac32f8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrerror.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrerror.h @@ -4,7 +4,7 @@ * * PFR error codes (specification only). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.c index a694ba1810..68849b4a11 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.c @@ -4,7 +4,7 @@ * * FreeType PFR glyph loader (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.h index 5886ed364e..81a0532783 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrgload.h @@ -4,7 +4,7 @@ * * FreeType PFR glyph loader (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.c index 07867b45da..1105ba4812 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.c @@ -4,7 +4,7 @@ * * FreeType PFR loader (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.h index f530a0a583..a2f3bcc3df 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrload.h @@ -4,7 +4,7 @@ * * FreeType PFR loader (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.c index 39ad3cc7df..9fdd84a86d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.c @@ -4,7 +4,7 @@ * * FreeType PFR object methods (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.h index 850bf5b4a6..3ad74e97d3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrobjs.h @@ -4,7 +4,7 @@ * * FreeType PFR object methods (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.c index ecea71d4fb..515089a65b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.c @@ -4,7 +4,7 @@ * * FreeType PFR bitmap loader (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.h index c5c27e36b1..639f8c8182 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrsbit.h @@ -4,7 +4,7 @@ * * FreeType PFR bitmap loader (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrtypes.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrtypes.h index 83461cb16b..54cc09ca39 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrtypes.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/pfrtypes.h @@ -4,7 +4,7 @@ * * FreeType PFR data structures (specification only). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/rules.mk index 56af03bcdf..842d88eac6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pfr/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2002-2025 by +# Copyright (C) 2002-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.c index b813efde4e..1cc8ab29d4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.c @@ -4,7 +4,7 @@ * * AFM parser (body). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.h index add8597717..02a9617b8d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/afmparse.h @@ -4,7 +4,7 @@ * * AFM parser (specification). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.c index 17bdd23c7d..908a811261 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.c @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (body). * - * Copyright (C) 2017-2025 by + * Copyright (C) 2017-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.h index e72ec043ba..0836a642b2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/cffdecode.h @@ -4,7 +4,7 @@ * * PostScript CFF (Type 2) decoding routines (specification). * - * Copyright (C) 2017-2025 by + * Copyright (C) 2017-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/module.mk index b9598f4345..2c6ddacb96 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psaux.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psaux.c index 37b5f8b2c6..f0c3c2ef97 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psaux.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psaux.c @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript driver component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxerr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxerr.h index 0d7fe2b612..5766482d1b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxerr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxerr.h @@ -4,7 +4,7 @@ * * PS auxiliary module error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.c index 942804190c..2f9eb87484 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.c @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.h index 4a5ebc1b60..e7fa15c34b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psauxmod.h @@ -4,7 +4,7 @@ * * FreeType auxiliary PostScript module implementation (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.c index 4567d3f3c0..3a054cbbf6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.c @@ -4,7 +4,7 @@ * * Some convenience conversions (body). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.h index 63735af411..fc123faea4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psconv.h @@ -4,7 +4,7 @@ * * Some convenience conversions (specification). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.c index 8159fd6ef1..5019f9925c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.c @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.h index 277aa1247c..04205f891b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/psobjs.h @@ -4,7 +4,7 @@ * * Auxiliary functions for PostScript fonts (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/rules.mk index cc4215fc5f..ace45afb46 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.c index 66493b6812..686ca7abdf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.c @@ -4,7 +4,7 @@ * * Type 1 character map support (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.h index 114bfbb041..be66a0c7f6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1cmap.h @@ -4,7 +4,7 @@ * * Type 1 character map support (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.c index c3fb343d4c..ece512412d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.c @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -458,6 +458,7 @@ FT_Bool large_int; FT_Fixed seed; + FT_UInt len_buildchar; T1_Hints_Funcs hinter; #ifdef FT_DEBUG_LEVEL_TRACE @@ -483,13 +484,16 @@ hinter = (T1_Hints_Funcs)builder->hints_funcs; - /* a font that reads BuildCharArray without setting */ - /* its values first is buggy, but ... */ - FT_ASSERT( ( decoder->len_buildchar == 0 ) == - ( decoder->buildchar == NULL ) ); + /* Cache `len_buildchar` locally so that a stray write to the */ + /* decoder structure during charstring processing cannot bypass */ + /* the bounds checks in callothersubr 19/24/25 handlers. */ + len_buildchar = decoder->len_buildchar; - if ( decoder->buildchar && decoder->len_buildchar > 0 ) - FT_ARRAY_ZERO( decoder->buildchar, decoder->len_buildchar ); + FT_ASSERT( ( len_buildchar == 0 ) == + ( decoder->buildchar == NULL ) ); + + if ( decoder->buildchar && len_buildchar > 0 ) + FT_ARRAY_ZERO( decoder->buildchar, len_buildchar ); zone->base = charstring_base; limit = zone->limit = charstring_base + charstring_len; @@ -969,8 +973,8 @@ idx = Fix2Int( top[0] ); - if ( idx < 0 || - (FT_UInt)idx + blend->num_designs > decoder->len_buildchar ) + if ( idx < 0 || + (FT_UInt)idx + blend->num_designs > len_buildchar ) goto Unexpected_OtherSubr; ft_memcpy( &decoder->buildchar[idx], @@ -1037,7 +1041,7 @@ idx = Fix2UInt( top[1] ); - if ( idx >= decoder->len_buildchar ) + if ( idx >= len_buildchar ) goto Unexpected_OtherSubr; decoder->buildchar[idx] = top[0]; @@ -1058,7 +1062,7 @@ idx = Fix2UInt( top[0] ); - if ( idx >= decoder->len_buildchar ) + if ( idx >= len_buildchar ) goto Unexpected_OtherSubr; top[0] = decoder->buildchar[idx]; @@ -1204,14 +1208,14 @@ #ifdef FT_DEBUG_LEVEL_TRACE - if ( decoder->len_buildchar > 0 ) + if ( len_buildchar > 0 ) { FT_UInt i; FT_TRACE4(( "BuildCharArray = [ " )); - for ( i = 0; i < decoder->len_buildchar; i++ ) + for ( i = 0; i < len_buildchar; i++ ) FT_TRACE4(( "%ld ", decoder->buildchar[i] )); FT_TRACE4(( "]\n" )); @@ -1523,6 +1527,15 @@ goto Syntax_Error; } + /* Ensure that popping an unknown 'othersubr' result does not */ + /* push the stack pointer past the end of the stack array. */ + if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS ) + { + FT_ERROR(( "t1_decoder_parse_charstrings:" + " stack overflow in pop\n" )); + goto Syntax_Error; + } + unknown_othersubr_result_cnt--; top++; /* `push' the operand to callothersubr onto the stack */ break; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.h index 7b913f55df..1b5d5205a8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psaux/t1decode.h @@ -4,7 +4,7 @@ * * PostScript Type 1 decoding routines (specification). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/module.mk index 0238368a33..96aa535228 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.c index e053dba17b..f169fc3459 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.c @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (body). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.h index f4aa854055..95d41b49aa 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshalgo.h @@ -4,7 +4,7 @@ * * PostScript hinting algorithm (specification). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.c index a772b66f30..2e4efea068 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.c @@ -5,7 +5,7 @@ * PostScript hinter global hinting management (body). * Inspired by the new auto-hinter module. * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.h index 555e99facb..0158b92ab9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshglob.h @@ -4,7 +4,7 @@ * * PostScript hinter global hinting management. * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshinter.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshinter.c index 140c7b2f92..f22de34bd4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshinter.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshinter.c @@ -4,7 +4,7 @@ * * FreeType PostScript Hinting module * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.c index c9f4a94fe9..f6b2e2df94 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.c @@ -4,7 +4,7 @@ * * FreeType PostScript hinter module implementation (body). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.h index de9c398e9f..d68ef9a873 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshmod.h @@ -4,7 +4,7 @@ * * PostScript hinter module interface (specification). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshnterr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshnterr.h index 7076664ddd..96bc3a3175 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshnterr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshnterr.h @@ -4,7 +4,7 @@ * * PS Hinter error codes (specification only). * - * Copyright (C) 2003-2025 by + * Copyright (C) 2003-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.c index 13754313fb..f14c9c7cbd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.c @@ -4,7 +4,7 @@ * * FreeType PostScript hints recorder (body). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.h index a79069f98d..0b644f5b96 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/pshrec.h @@ -4,7 +4,7 @@ * * Postscript (Type1/Type2) hints recorder (specification). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/rules.mk index 6c3066b83d..7a3b8f5e33 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/pshinter/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2001-2025 by +# Copyright (C) 2001-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/module.mk index 9a645532a5..bcda0067c8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.c index c5d71edad8..5409c61faf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.c @@ -4,7 +4,7 @@ * * psnames module implementation (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.h index 482fd0a36d..7a619d83fb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psmodule.h @@ -4,7 +4,7 @@ * * High-level psnames module interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnamerr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnamerr.h index 17987f9cd4..bef9e797c8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnamerr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnamerr.h @@ -4,7 +4,7 @@ * * PS names module error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnames.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnames.c index 77ea42c516..b0ade9874d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnames.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/psnames.c @@ -4,7 +4,7 @@ * * FreeType psnames module component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/pstables.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/pstables.h index 65ce6c0b47..8a32aac325 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/pstables.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/pstables.h @@ -4,7 +4,7 @@ * * PostScript glyph names. * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/rules.mk index 71bfd64e19..7b0f1d6b47 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/psnames/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftmisc.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftmisc.h index 9d97223e94..cf96cd09ed 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftmisc.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftmisc.h @@ -5,7 +5,7 @@ * Miscellaneous macros for stand-alone rasterizer (specification * only). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.c index 807d444e7a..4165800a1a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -546,7 +546,7 @@ * */ - if ( High ) + if ( High && ras.bTop + ras.bRight < 256 ) { ras.precision_bits = 12; ras.precision_step = 256; @@ -1351,17 +1351,9 @@ /* this arc has no given direction, split it! */ Split_Conic( arc ); arc += 2; + continue; } - else if ( y1 == y3 ) - { - /* this arc is flat, advance position */ - /* and pop it from the Bezier stack */ - arc -= 2; - - ras.lastX = x3; - ras.lastY = y3; - } - else + else if ( y1 != y3 ) { /* the arc is y-monotonous, either ascending or descending */ /* detect a change of direction */ @@ -1389,13 +1381,16 @@ if ( Bezier_Down( RAS_VARS 2, arc, Split_Conic, ras.minY, ras.maxY ) ) goto Fail; - arc -= 2; - - ras.lastX = x3; - ras.lastY = y3; } - } while ( arc >= arcs ); + ras.lastX = x3; + ras.lastY = y3; + + if ( arc == arcs ) + break; + arc -= 2; + + } while ( 1 ); return SUCCESS; @@ -1498,17 +1493,9 @@ /* this arc has no given direction, split it! */ Split_Cubic( arc ); arc += 3; + continue; } - else if ( y1 == y4 ) - { - /* this arc is flat, advance position */ - /* and pop it from the Bezier stack */ - arc -= 3; - - ras.lastX = x4; - ras.lastY = y4; - } - else + else if ( y1 != y4 ) { state_bez = y1 < y4 ? Ascending_State : Descending_State; @@ -1535,13 +1522,16 @@ if ( Bezier_Down( RAS_VARS 3, arc, Split_Cubic, ras.minY, ras.maxY ) ) goto Fail; - arc -= 3; - - ras.lastX = x4; - ras.lastY = y4; } - } while ( arc >= arcs ); + ras.lastX = x4; + ras.lastY = y4; + + if ( arc == arcs ) + break; + arc -= 3; + + } while ( 1 ); return SUCCESS; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.h index 64499bf955..e20184ddc8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftraster.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.c index 3fa008704e..6b28cb0bf8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.c @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.h index d838a942b0..92249a0cb9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/ftrend1.h @@ -4,7 +4,7 @@ * * The FreeType glyph rasterizer interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/module.mk index 7292b72d9a..7f7567c07e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/raster.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/raster.c index 1b1be144a5..df2ec38d42 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/raster.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/raster.c @@ -4,7 +4,7 @@ * * FreeType monochrome rasterer module component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rasterrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rasterrs.h index 39d82a8051..744d179cd8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rasterrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rasterrs.h @@ -4,7 +4,7 @@ * * monochrome renderer error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rules.mk index 0ae560e8a9..90af6d1852 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/raster/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftbsdf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftbsdf.c index d4c5115ea6..d70ebbf173 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftbsdf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftbsdf.c @@ -4,7 +4,7 @@ * * Signed Distance Field support for bitmap fonts (body only). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. @@ -113,6 +113,7 @@ * // copy SDF data to the target bitmap * copy(dm to t); * } + * ``` * */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.c index 10d572b319..e86b995946 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.c @@ -4,7 +4,7 @@ * * Signed Distance Field support for outline fonts (body). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. @@ -3281,6 +3281,11 @@ goto Exit; } + if ( bitmap->rows > FT_INT_MAX / bitmap->width ) + { + error = FT_THROW( Array_Too_Large ); + goto Exit; + } if ( FT_NEW_ARRAY( dists, bitmap->rows * bitmap->width ) ) goto Exit; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.h index fb17580362..9bf17d1d91 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdf.h @@ -4,7 +4,7 @@ * * Signed Distance Field support (specification). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.c index fa99944f84..ffbf7a46a4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.c @@ -4,7 +4,7 @@ * * Auxiliary data for Signed Distance Field support (body). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.h index b87e97ed38..d62e00fa39 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfcommon.h @@ -4,7 +4,7 @@ * * Auxiliary data for Signed Distance Field support (specification). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdferrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdferrs.h index e28e2e1cad..5bb8f05bbe 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdferrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdferrs.h @@ -4,7 +4,7 @@ * * Signed Distance Field error codes (specification only). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.c index e24b3b614b..1f50ec447a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.c @@ -4,7 +4,7 @@ * * Signed Distance Field renderer interface (body). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.h index ab98a79632..bb362949af 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/ftsdfrend.h @@ -4,7 +4,7 @@ * * Signed Distance Field renderer interface (specification). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/module.mk index 2585c7d098..d8d0d49f6f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2020-2025 by +# Copyright (C) 2020-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/rules.mk index 689ed8fcfc..92ed750664 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2020-2025 by +# Copyright (C) 2020-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/sdf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/sdf.c index 7f02d9a59d..21dfe6650b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/sdf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sdf/sdf.c @@ -4,7 +4,7 @@ * * FreeType Signed Distance Field renderer module component (body only). * - * Copyright (C) 2020-2025 by + * Copyright (C) 2020-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Written by Anuj Verma. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/module.mk index 845fb99971..5ed9ce0aa8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.c index 24fb345559..e588e6b380 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.c @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.h index c59199e60d..f187b639a1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/pngshim.h @@ -4,7 +4,7 @@ * * PNG Bitmap glyph support. * - * Copyright (C) 2013-2025 by + * Copyright (C) 2013-2026 by * Google, Inc. * Written by Stuart Gill and Behdad Esfahbod. * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/rules.mk index 8e353ed2b5..791d329a09 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.c index 32291e23e3..4046b1a0cd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.c @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.h index be4e33166c..e9eed184b7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfdriver.h @@ -4,7 +4,7 @@ * * High-level SFNT driver interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sferrors.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sferrors.h index 2da4ac776b..05b259c1bf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sferrors.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sferrors.h @@ -4,7 +4,7 @@ * * SFNT error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfnt.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfnt.c index 84f6ad5156..2eab87f2fd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfnt.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfnt.c @@ -4,7 +4,7 @@ * * Single object library component. * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.c index 6af35787e8..fc855cbb6b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.c @@ -4,7 +4,7 @@ * * SFNT object management (base). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.h index 8c38b72795..a27ad7064a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfobjs.h @@ -4,7 +4,7 @@ * * SFNT object management (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.c index 015c7b78b4..b8a3030d9c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.c @@ -4,7 +4,7 @@ * * WOFF format management (base). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.h index df7ace5c20..a563fcc682 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff.h @@ -4,7 +4,7 @@ * * WOFFF format management (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.c index 41c233597b..013e30fc52 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.c @@ -4,7 +4,7 @@ * * WOFF2 format management (base). * - * Copyright (C) 2019-2025 by + * Copyright (C) 2019-2026 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.h index 588761d0c8..e0296d8260 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/sfwoff2.h @@ -4,7 +4,7 @@ * * WOFFF2 format management (specification). * - * Copyright (C) 2019-2025 by + * Copyright (C) 2019-2026 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.c index 4aa1827032..9fa12c099f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (body). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.h index abcce2cc6e..87d210e52f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttbdf.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded BDF properties (specification). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.c index 91b0234422..f5837e65e8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.c @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.h index 645e9e37e0..fdb34f525e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmap.h @@ -4,7 +4,7 @@ * * TrueType character mapping table (cmap) support (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmapc.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmapc.h index 65807bb737..c17ac5bba1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmapc.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcmapc.h @@ -4,7 +4,7 @@ * * TT CMAP classes definitions (specification only). * - * Copyright (C) 2009-2025 by + * Copyright (C) 2009-2026 by * Oran Agra and Mickey Gabel. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.c index 7929b7aaf4..b22e279b34 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.c @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (body). * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg. * * Originally written by Shao Yu Zhang . @@ -236,8 +236,10 @@ p1 = (FT_Byte*)( table + base_glyphs_offset_v1 ); num_base_glyphs_v1 = FT_PEEK_ULONG( p1 ); - if ( ( table_size - base_glyphs_offset_v1 ) / BASE_GLYPH_PAINT_RECORD_SIZE - < num_base_glyphs_v1 ) + /* Account for 4 byte numBaseGlyphPaintRecords at the beginning of */ + /* the BaseGlyphPaintRecord array. */ + if ( ( table_size - base_glyphs_offset_v1 - 4 ) / + BASE_GLYPH_PAINT_RECORD_SIZE < num_base_glyphs_v1 ) goto InvalidTable; colr->num_base_glyphs_v1 = num_base_glyphs_v1; @@ -451,20 +453,14 @@ FT_UInt *acolor_index, FT_LayerIterator* iterator ) { - Colr* colr = (Colr*)face->colr; - BaseGlyphRecord glyph_record; - - - if ( !colr ) - return 0; - - if ( !iterator->p ) + if ( !iterator->p ) /* first call to function */ { - FT_ULong offset; + Colr* colr = (Colr*)face->colr; + BaseGlyphRecord glyph_record; - /* first call to function */ - iterator->layer = 0; + if ( !colr ) + return 0; if ( !find_base_glyph_record( colr->base_glyphs, colr->num_base_glyphs, @@ -472,21 +468,18 @@ &glyph_record ) ) return 0; - if ( glyph_record.num_layers ) - iterator->num_layers = glyph_record.num_layers; - else + if ( glyph_record.num_layers == 0 || + glyph_record.first_layer_index + glyph_record.num_layers > + colr->num_layers ) return 0; - offset = LAYER_SIZE * glyph_record.first_layer_index; - if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size ) - return 0; - - iterator->p = colr->layers + offset; + iterator->num_layers = glyph_record.num_layers; + iterator->layer = 0; + iterator->p = colr->layers + + LAYER_SIZE * glyph_record.first_layer_index; } - if ( iterator->layer >= iterator->num_layers || - iterator->p < colr->layers || - iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) ) + if ( iterator->layer >= iterator->num_layers ) return 0; *aglyph_index = FT_NEXT_USHORT( iterator->p ); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.h index 3913acc74d..c7bf1f2a4a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcolr.h @@ -4,7 +4,7 @@ * * TrueType and OpenType colored glyph layer support (specification). * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.c index 6d1208f6af..04e2db1eab 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.c @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (body). * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.h index a0b4c9d927..5c2e660e13 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttcpal.h @@ -4,7 +4,7 @@ * * TrueType and OpenType color palette support (specification). * - * Copyright (C) 2018-2025 by + * Copyright (C) 2018-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Originally written by Shao Yu Zhang . diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.c index 12882fd708..6f9bddf34a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.c @@ -4,7 +4,7 @@ * * Routines to parse and access the 'GPOS' table for simple kerning (body). * - * Copyright (C) 2025 by + * Copyright (C) 2025-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -408,6 +408,8 @@ FT_UInt class1Count; FT_UInt class2Count; + FT_UInt max_size; + /* The number of coverage indices is not relevant here. */ if ( !tt_face_validate_coverage( coverage, table_limit, FT_UINT_MAX ) ) @@ -432,7 +434,11 @@ /* For our purposes, the first value record only contains */ /* X advances while the second one is empty. */ - limit = p + class1Count * class2Count * 2; + max_size = class1Count * class2Count; + if ( max_size > FT_UINT_MAX / 2 ) + return FALSE; + + limit = p + max_size * 2; if ( table_limit < limit ) return FALSE; @@ -713,7 +719,7 @@ return error; Fail: - FT_FREE( gpos ); + FT_FRAME_RELEASE( gpos ); FT_FREE( gpos_lookups_kerning ); FT_FREE( use_lookup_table ); @@ -817,7 +823,7 @@ /* XXX: Is this modulo 65536 arithmetic? */ if ( startGlyphID <= glyph_index && - startGlyphID + glyphCount >= glyph_index ) + startGlyphID + glyphCount > glyph_index ) return FT_PEEK_USHORT( p + ( glyph_index - startGlyphID ) * 2 ); } else @@ -884,7 +890,7 @@ if ( second_glyph > mid_index ) - min = max + 1; + min = mid + 1; else if ( second_glyph < mid_index ) max = mid; else diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.h index eebc22e9ec..3c227445ba 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttgpos.h @@ -5,7 +5,7 @@ * Routines to parse and access the 'GPOS' table for simple kerning * (specification). * - * Copyright (C) 2024-2025 by + * Copyright (C) 2024-2026 by * David Saltzman * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.c index 76618b0d3b..65b249ff4c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.c @@ -4,7 +4,7 @@ * * Routines to parse and access the 'kern' table for kerning (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.h index e0075dce61..8cc912a79e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttkern.h @@ -5,7 +5,7 @@ * Routines to parse and access the 'kern' table for kerning * (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.c index 0c257ce4d3..e17d07a971 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.c @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.h index e3666c901b..0a0aab24ce 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttload.h @@ -5,7 +5,7 @@ * Load the basic TrueType tables, i.e., tables that can be either in * TTF or OTF fonts (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.c index 541d844747..60dce87d84 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.c @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (body). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.h index 1ee84507f1..618e04ffd2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttmtx.h @@ -4,7 +4,7 @@ * * Load the metrics tables common to TTF and OTF fonts (specification). * - * Copyright (C) 2006-2025 by + * Copyright (C) 2006-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.c index 4246b6c8ef..98603e115e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.c @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.h index a11b669685..896118015e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttpost.h @@ -5,7 +5,7 @@ * PostScript name table processing for TrueType and OpenType fonts * (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.c index 34e4561981..1655e40b68 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.c @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (body). * - * Copyright (C) 2005-2025 by + * Copyright (C) 2005-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * Copyright 2013 by Google, Inc. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.h index 7427149d68..8fd4522326 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsbit.h @@ -4,7 +4,7 @@ * * TrueType and OpenType embedded bitmap support (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.c index c7b83b2b7d..79cf531d05 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.c @@ -4,7 +4,7 @@ * * OpenType SVG Color (specification). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.h index d2e127d6df..6253ed1d49 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/ttsvg.h @@ -4,7 +4,7 @@ * * OpenType SVG Color (specification). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.c index 0f9e3889aa..1c3779d9f3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.c @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (base). * - * Copyright (C) 2019-2025 by + * Copyright (C) 2019-2026 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.h index e223022962..200262d386 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/sfnt/woff2tags.h @@ -4,7 +4,7 @@ * * WOFF2 Font table tags (specification). * - * Copyright (C) 2019-2025 by + * Copyright (C) 2019-2026 by * Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.c index 3c387aea0a..0f7b63937d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.c @@ -4,7 +4,7 @@ * * A new `perfect' anti-aliasing renderer (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.h index e463e5b3eb..99c7383e76 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftgrays.h @@ -4,7 +4,7 @@ * * FreeType smooth renderer declaration * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmerrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmerrs.h index 8d5068549f..2f2276bd58 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmerrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmerrs.h @@ -4,7 +4,7 @@ * * smooth renderer error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.c index 5a7a852a61..7378e6adc4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.c @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (body). * - * Copyright (C) 2000-2025 by + * Copyright (C) 2000-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.h index f76708ae70..56c7ac70b5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/ftsmooth.h @@ -4,7 +4,7 @@ * * Anti-aliasing renderer interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/module.mk index 4d06c54c3e..f09f29423c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/rules.mk index 289c0c86ee..1cdda6d839 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/smooth.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/smooth.c index 23dc7accf9..4ecd3ccdb9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/smooth.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/smooth/smooth.c @@ -4,7 +4,7 @@ * * FreeType anti-aliasing rasterer module component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.c index 0b3f6857d2..c98d7f7db9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.c @@ -4,7 +4,7 @@ * * The FreeType SVG renderer interface (body). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.h index b04c7fef15..6254485c5a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/ftsvg.h @@ -4,7 +4,7 @@ * * The FreeType SVG renderer interface (specification). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/module.mk index 4c7b18b22b..5a93e17436 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2022-2025 by +# Copyright (C) 2022-2026 by # David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/rules.mk index 65038b7391..53f4629f8c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2022-2025 by +# Copyright (C) 2022-2026 by # David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svg.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svg.c index c64755c0a9..fff03ee59e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svg.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svg.c @@ -4,7 +4,7 @@ * * FreeType SVG renderer module component (body only). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svgtypes.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svgtypes.h index 65b3eacb6e..f731bdf111 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svgtypes.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/svg/svgtypes.h @@ -4,7 +4,7 @@ * * The FreeType SVG renderer internal types (specification). * - * Copyright (C) 2022-2025 by + * Copyright (C) 2022-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/afblue.pl b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/afblue.pl index a9a2fa3b81..24d01cd1ff 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/afblue.pl +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/afblue.pl @@ -5,7 +5,7 @@ # # Process a blue zone character data file. # -# Copyright (C) 2013-2025 by +# Copyright (C) 2013-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/glnames.py b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/glnames.py index c780ac3f37..9dc28dbc86 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/glnames.py +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/glnames.py @@ -3,7 +3,7 @@ # # FreeType 2 glyph name builder # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/update-copyright-year b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/update-copyright-year index f7a25a58f7..2b19d01fa1 100755 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/update-copyright-year +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/tools/update-copyright-year @@ -2,7 +2,7 @@ eval '(exit $?0)' && eval 'exec perl -wS -i "$0" ${1+"$@"}' & eval 'exec perl -wS -i "$0" $argv:q' if 0; -# Copyright (C) 2015-2025 by +# Copyright (C) 2015-2026 by # Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/module.mk index d7ba01b925..e4627b6691 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/rules.mk index a5e0d4afdd..052f2fef21 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/truetype.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/truetype.c index bc8048d0f5..accec4597d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/truetype.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/truetype.c @@ -4,7 +4,7 @@ * * FreeType TrueType driver component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.c index 6369d83d6d..90d6e81057 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.c @@ -4,7 +4,7 @@ * * TrueType font driver implementation (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.h index 943eaae348..c00bba066e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttdriver.h @@ -4,7 +4,7 @@ * * High-level TrueType driver interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/tterrors.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/tterrors.h index 631dbf5a80..1ae4b087ac 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/tterrors.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/tterrors.h @@ -4,7 +4,7 @@ * * TrueType error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.c index 4dd68ab101..dcff7c3bb7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.c @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -1185,9 +1185,7 @@ /* make room for phantom points */ - error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, - outline->n_points + 4, - 0 ); + error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader, 4, 0 ); if ( error ) return error; @@ -1425,6 +1423,14 @@ FT_TRACE5(( " nesting level: %u\n", recurse_count )); #endif + /* arbitrary recursion limit */ + if ( recurse_count > 100 ) + { + FT_TRACE4(( "load_truetype_glyph: recursion depth exceeded\n" )); + error = FT_THROW( Invalid_Composite ); + goto Exit; + } + /* some fonts have an incorrect value of `maxComponentDepth' */ if ( recurse_count > face->max_profile.maxComponentDepth ) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.h index 39d6ae3664..3d6a762d1f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgload.h @@ -4,7 +4,7 @@ * * TrueType Glyph Loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.c index 1bfcdc8d9b..5ab6e17119 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.c @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, Werner Lemberg, and George Williams. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.h index 568c8027bb..8a59c0cd6e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttgxvar.h @@ -4,7 +4,7 @@ * * TrueType GX Font Variation loader (specification) * - * Copyright (C) 2004-2025 by + * Copyright (C) 2004-2026 by * David Turner, Robert Wilhelm, Werner Lemberg and George Williams. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.c index f46cc77fe5..f850bc418e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.c @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.h index 5cdc8f59f1..05ac831dfd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttinterp.h @@ -4,7 +4,7 @@ * * TrueType bytecode interpreter (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.c index 2aedbd842c..dc89768858 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.c @@ -4,7 +4,7 @@ * * Objects manager (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, @@ -734,6 +734,10 @@ /* a `loca' table is not valid */ if ( face->glyf_len && FT_ERR_EQ( error, Table_Missing ) ) goto Exit; + /* if both `glyf' and `loca' tables are missing, */ + /* we don't have a valid font file either */ + if ( face->glyf_len == 0 && FT_ERR_EQ( error, Locations_Missing ) ) + goto Bad_Format; if ( error ) goto Exit; } @@ -1057,9 +1061,23 @@ exec->maxFunc = 0; exec->maxIns = 0; - /* XXX: We reserve a little more elements on the stack to deal */ - /* with broken fonts like arialbs, courbs, timesbs, etc. */ - exec->stackSize = maxp->maxStackElements + 32; + /* We reserve extra elements on the stack to deal with broken fonts. */ + /* */ + /* Some fonts (e.g., `Rubik-Italic.ttf`) have buggy hinting bytecode */ + /* that pushes more values than `maxStackElements` declared in the */ + /* 'maxp' table. For example, `Rubik-Italic.ttf`'s 'prep' program */ + /* pushes 255 values but `maxStackElements` is only set to 153. */ + /* */ + /* To alleviate this situation we increase the value of */ + /* `maxStackElements` based on a percentage of `maxStackElements`, */ + /* with a minimum of 128 extra slots. This allows most broken fonts */ + /* to work without completely disabling hinting, while adding only a */ + /* small overhead for correctly authored fonts. */ + + /* Use 50% more than declared, with minimum safety margin of 128. */ + exec->stackSize = maxp->maxStackElements + + FT_MAX( maxp->maxStackElements / 2, 128 ); + exec->storeSize = maxp->maxStorage; exec->cvtSize = face->cvt_size; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.h index 28d6c7d855..9b2f412ac4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttobjs.h @@ -4,7 +4,7 @@ * * Objects manager (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.c index 827454d857..5b0a3944d6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.c @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.h index bb4d3c9cc5..ad0a9eb7a6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/truetype/ttpload.h @@ -4,7 +4,7 @@ * * TrueType-specific tables loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/module.mk index e7c0718de4..a0aeada3eb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/rules.mk index 2cb9c34d14..5d9c2e7e4f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.c index b1a0d23bed..cc94a0d4a4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.c @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.h index 92ff627dd0..f31c9d100f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1afm.h @@ -4,7 +4,7 @@ * * AFM support for Type 1 fonts (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.c index 5ded771402..1d7a342708 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.c @@ -4,7 +4,7 @@ * * Type 1 driver interface (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.h index 1cc3d24e7d..2869adab6e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1driver.h @@ -4,7 +4,7 @@ * * High-level Type 1 driver interface (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1errors.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1errors.h index 46bddbc30f..efe53be1f4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1errors.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1errors.h @@ -4,7 +4,7 @@ * * Type 1 error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.c index b9bc0b56ce..dd9b6cd80f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.c @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.h index 6bedd132c5..b3de427a2f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1gload.h @@ -4,7 +4,7 @@ * * Type 1 Glyph Loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.c index 0f11445bef..1d095f8ac1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.c @@ -4,7 +4,7 @@ * * Type 1 font loader (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.h index 2cd8241968..39d4b94e9d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1load.h @@ -4,7 +4,7 @@ * * Type 1 font loader (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.c index 7f25208f87..4ee0a59109 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.c @@ -4,7 +4,7 @@ * * Type 1 objects manager (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.h index 6c71977c15..f152f630a8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1objs.h @@ -4,7 +4,7 @@ * * Type 1 objects manager (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.c index ef643e298f..a9b8d18a6f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.c @@ -4,7 +4,7 @@ * * Type 1 parser (body). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.h index f4ad426e9e..ebd7c3fb34 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1parse.h @@ -4,7 +4,7 @@ * * Type 1 parser (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1tokens.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1tokens.h index a526406a41..745351a34c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1tokens.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/t1tokens.h @@ -4,7 +4,7 @@ * * Type 1 tokenizer (specification). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/type1.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/type1.c index ba053ebd63..b8e88e6eac 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/type1.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type1/type1.c @@ -4,7 +4,7 @@ * * FreeType Type 1 driver component (body only). * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/module.mk index 1cd3d4eaaf..d87f3a404e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2002-2025 by +# Copyright (C) 2002-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/rules.mk index 7f7bb9c06a..3c796cee85 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 2002-2025 by +# Copyright (C) 2002-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.c index 234fb16f9c..a45d13ebd1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.c @@ -4,7 +4,7 @@ * * High-level Type 42 driver interface (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.h index d286da02a5..1c2bb2029a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42drivr.h @@ -4,7 +4,7 @@ * * High-level Type 42 driver interface (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42error.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42error.h index f7c9a9403f..9c386d8c48 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42error.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42error.h @@ -4,7 +4,7 @@ * * Type 42 error codes (specification only). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.c index d20917aea2..a01c3129d0 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.c @@ -4,7 +4,7 @@ * * Type 42 objects manager (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.h index 69a0fcd2fd..15767f8716 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42objs.h @@ -4,7 +4,7 @@ * * Type 42 objects manager (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.c index 55a29fecb2..d645be2a01 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.c @@ -4,7 +4,7 @@ * * Type 42 font parser (body). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.h index f8d0a8b265..4e61169a87 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42parse.h @@ -4,7 +4,7 @@ * * Type 42 font parser (specification). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42types.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42types.h index 72614b1799..b0bf9e8ecf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42types.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/t42types.h @@ -4,7 +4,7 @@ * * Type 42 font data types (specification only). * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * Roberto Alameda. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/type42.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/type42.c index 82abeed7b8..da1e6214d3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/type42.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/type42/type42.c @@ -4,7 +4,7 @@ * * FreeType Type 42 driver component. * - * Copyright (C) 2002-2025 by + * Copyright (C) 2002-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/fnterrs.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/fnterrs.h index 9eae20aaec..b2644edbf3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/fnterrs.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/fnterrs.h @@ -4,7 +4,7 @@ * * Win FNT/FON error codes (specification only). * - * Copyright (C) 2001-2025 by + * Copyright (C) 2001-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/module.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/module.mk index 2d6f64a0a6..d49dc9d3b2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/module.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/module.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/rules.mk b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/rules.mk index 3df3282990..b65bb4c41a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/rules.mk +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/rules.mk @@ -3,7 +3,7 @@ # -# Copyright (C) 1996-2025 by +# Copyright (C) 1996-2026 by # David Turner, Robert Wilhelm, and Werner Lemberg. # # This file is part of the FreeType project, and may only be used, modified, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.c b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.c index 2653a2ecc1..264185058a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.c @@ -4,7 +4,7 @@ * * FreeType font driver for Windows FNT/FON files * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * Copyright 2003 Huw D M Davies for Codeweavers * Copyright 2007 Dmitry Timoshkov for Codeweavers diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.h b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.h index 56706450fa..420e11e3c6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/freetype/src/winfonts/winfnt.h @@ -4,7 +4,7 @@ * * FreeType font driver for Windows FNT/FON files * - * Copyright (C) 1996-2025 by + * Copyright (C) 1996-2026 by * David Turner, Robert Wilhelm, and Werner Lemberg. * Copyright 2007 Dmitry Timoshkov for Codeweavers * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/README.md b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/README.md index df4d67a9e5..494ed24eaa 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/README.md +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/README.md @@ -14,10 +14,64 @@ -HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also -[Apple Advanced Typography][2]. -Check “[What is HarfBuzz?](https://harfbuzz.github.io/what-is-harfbuzz.html)” chapter -in the user manual for more inforamation on what HarfBuzz do and what it doesn’t do. +HarfBuzz started as a text shaping engine but has grown into a +full font platform — the `ffmpeg` of text shaping. It primarily +supports [OpenType][1], but also [Apple Advanced Typography][2]. + +HarfBuzz shapes the majority of text on modern screens. + +HarfBuzz is optimized for robustness, correctness, and performance +— in that order. Achieve all. + +**[Try it live at harfbuzz-world.cc](https://harfbuzz-world.cc/)** — an interactive playground for shaping, subsetting, rasterization, vector output, and GPU rendering, all running in your browser. + +Here is a quick map of its components: + +### Core libraries + +| Library | Description | +|---------|-------------| +| **libharfbuzz** | Text shaping, draw API, paint API. Highly configurable (see [CONFIG.md](CONFIG.md)). Optional integration backends compiled in: hb-ft (FreeType), hb-coretext (macOS), hb-uniscribe (Windows), hb-directwrite (Windows), hb-gdi (Windows), hb-glib, hb-graphite2. | +| **libharfbuzz-subset** | Font subsetting and variable-font instancing. | + +### Auxiliary libraries + +| Library | Description | +|---------|-------------| +| **libharfbuzz-icu** | ICU Unicode integration. | +| **libharfbuzz-cairo** | Cairo rendering integration. | +| **libharfbuzz-gobject** | GObject/GI bindings. | + +### Experimental libraries + +| Library | Description | +|---------|-------------| +| **libharfbuzz-raster** | Glyph rasterization to bitmaps, including color fonts. Uses hb-draw and hb-paint. | +| **libharfbuzz-vector** | Glyph output to vector formats (currently SVG), including color fonts. Uses hb-draw and hb-paint. | +| **libharfbuzz-gpu** | Encodes glyph outlines for GPU rasterization (Slug algorithm). Provides shader sources in GLSL, WGSL, MSL, and HLSL. [Live demo.](https://harfbuzz.github.io/hb-gpu-demo/) | + +Notable missing feature: font hinting (including autohinting) +is not implemented. For hinted rasterization, use FreeType or +Skrifa. + +For simplified builds, amalgamated sources are available: +`harfbuzz.cc` (just libharfbuzz), `harfbuzz-subset.cc` (just +libharfbuzz-subset), or `harfbuzz-world.cc` (everything, driven +by a custom `hb-features.h`). For a live in-browser playground +plus a worked example of the world.cc single-file build, see +[harfbuzz-world.cc][26]. + +### Command-line tools + +| Tool | Description | +|------|-------------| +| **hb-shape** | Shape text and display glyph output. | +| **hb-view** | Render shaped text to an image. | +| **hb-subset** | Subset and optimize fonts. | +| **hb-info** | Display font metadata. | +| **hb-raster** | Render glyphs to bitmap images. | +| **hb-vector** | Render glyphs to vector formats (SVG). | +| **hb-gpu** | Interactive GPU text rendering. | The canonical source tree and bug trackers are available on [github][4]. Both development and user support discussion around HarfBuzz happen on @@ -45,9 +99,8 @@ For user manual as well as API documentation, check: https://harfbuzz.github.io ## Download -Tarball releases of HarfBuzz are available on [github releases][3] page. At the same place you -will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL, -`hb-view.exe`, `hb-shape.exe`, and all dependencies. +Tarball releases and Win32/Win64 binary bundles are available on the +[github releases][3] page. ## Development @@ -67,12 +120,12 @@ To report bugs or submit patches please use [github][4] issues and pull-requests To get a better idea of where HarfBuzz stands in the text rendering stack you may want to read [State of Text Rendering 2024][6]. -Here are a few presentation slides about HarfBuzz at the -Internationalization and Unicode Conference over the years: +Here are a few presentation slides about HarfBuzz over the years: +- 2026 – [HarfBuzz at 20!][25] +- 2016 – [Ten Years of HarfBuzz][20] - 2014 – [Unicode, OpenType, and HarfBuzz: Closing the Circle][7] - 2012 – [HarfBuzz, The Free and Open Text Shaping Engine][8] -- 2016 – [Ten Years of HarfBuzz][20] - 2009 – [HarfBuzz: the Free and Open Shaping Engine][9] More presentations and papers are available on [behdad][11]'s website. @@ -95,9 +148,18 @@ In particular, the following _studies_ are relevant to HarfBuzz development: ## Name -HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”, -transliterated using the Latin script. It also means "talkative" or -"glib" (also a nod to the GNOME project where HarfBuzz originates from). +HarfBuzz /hærfˈbɒːz/ + +From Persian حرف (*Harf*: letter) and باز (*Buzz*: open). +Transliteration of the Persian calque for *OpenType*. + +As a noun: *The* Open Source *text shaping* engine. + +As an adjective: Insincerely talkative; glib. A nod to the +GNOME project where HarfBuzz originates from. + +The logo shows حرف‌باز in the IranNastaliq font, on a Damascus +steel background. > Background: Originally there was this font format called TrueType. People and > companies started calling their type engines all things ending in Type: @@ -106,14 +168,15 @@ transliterated using the Latin script. It also means "talkative" or > with the concept but use the Persian translation. Which is fitting given that > Persian is written in the Arabic script, and OpenType is an extension of > TrueType that adds support for complex script rendering, and HarfBuzz is an -> implementation of OpenType complex text shaping. +> implementation of OpenType text shaping. ## Users -HarfBuzz is used in Android, Chrome, -ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX, Scribus, -PlayStation, Microsoft Edge, Amazon Kindle, Adobe Photoshop, Illustrator, -InDesign, Godot Engine, Unreal Engine, QuarkXPress, Figma, and other places. +HarfBuzz is used in Android, Chrome, ChromeOS, Firefox, GNOME, GTK+, KDE, +Qt, LibreOffice, OpenJDK, XeTeX, Adobe Photoshop, Illustrator, InDesign, +Microsoft Edge, Amazon Kindle, PlayStation, Godot Engine, Unreal Engine, +Figma, Canva, QuarkXPress, Scribus, smart TVs, +car displays, and many other places.

@@ -153,3 +216,5 @@ InDesign, Godot Engine, Unreal Engine, QuarkXPress, Figma, and other places. [22]: https://docs.google.com/document/d/1aH_waagdEM5UhslQxCeFEb82ECBhPlZjy5_MwLNLBYo/preview [23]: https://docs.google.com/document/d/1hRd5oYQJLrt0JuwWhEJWi7wh_9rbaIJkX6IR9DW7rZQ/preview [24]: https://docs.google.com/document/d/1a3K6fHjsiWW36vSzwJwCwEBOgznunKs80PSpBbpfHiA/preview +[25]: https://docs.google.com/presentation/d/1o9Exz1c-Lr-dJjA8dcBn_Vl_Y37cupmFzmclMjBE_Bc/view +[26]: https://harfbuzz-world.cc/ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/qt_attribution.json b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/qt_attribution.json index c6d4c005d0..e2cfc79d8a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/qt_attribution.json +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "HarfBuzz is an OpenType text shaping engine.", "Homepage": "http://harfbuzz.org", - "Version": "13.0.0", - "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/13.0.0", + "Version": "14.2.0", + "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/14.2.0", "PURL": "pkg:github/harfbuzz/harfbuzz@$", "CPE": "cpe:2.3:a:harfbuzz_project:harfbuzz:$:*:*:*:*:*:*:*", "License": "MIT License", diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh index 63d59af6ca..62d3a3ce1b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh @@ -525,7 +525,13 @@ struct ColorLine hb_paint_extend_t get_extend () const { - return (hb_paint_extend_t) (unsigned int) extend; + switch ((unsigned int) extend) + { + case Extend::EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT; + case Extend::EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT; + case Extend::EXTEND_PAD: + default: return HB_PAINT_EXTEND_PAD; + } } HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line, @@ -1520,9 +1526,9 @@ struct PaintComposite void paint_glyph (hb_paint_context_t *c) const { TRACE_PAINT (this); - c->funcs->push_group (c->data); + c->funcs->push_group_for (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); c->recurse (this+backdrop); - c->funcs->push_group (c->data); + c->funcs->push_group_for (c->data, (hb_paint_composite_mode_t) (int) mode); c->recurse (this+src); c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); @@ -1814,10 +1820,7 @@ struct ClipList { auto *rec = clips.as_array ().bsearch (gid); if (rec) - { - rec->get_extents (extents, this, instancer); - return true; - } + return rec->get_extents (extents, this, instancer); return false; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh index 2b8b69b600..9364fd9395 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh @@ -172,7 +172,7 @@ struct CPAL bool has_data () const { return numPalettes; } - unsigned int get_size () const + size_t get_size () const { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); } unsigned int get_palette_count () const { return numPalettes; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh index bb0e83e2eb..b5760053a3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh @@ -79,7 +79,7 @@ struct SBIXGlyph struct SBIXStrike { - static unsigned int get_size (unsigned num_glyphs) + static size_t get_size (unsigned num_glyphs) { return min_size + num_glyphs * HBUINT32::static_size; } bool sanitize (hb_sanitize_context_t *c) const diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh index ac70ce17dd..b89894c64a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh @@ -27,8 +27,10 @@ #include "../../../hb-open-type.hh" #include "../../../hb-blob.hh" +#include "../../../hb-limits.hh" #include "../../../hb-map.hh" #include "../../../hb-paint.hh" +#include "../../../hb-zlib.hh" #include #include @@ -42,6 +44,50 @@ namespace OT { +static inline hb_blob_t * +hb_ot_svg_reference_normalized_blob (hb_blob_t *image, + const char **svg, + unsigned *len) +{ + hb_blob_t *blob = hb_blob_reference (image); + unsigned data_len = 0; + const char *data = hb_blob_get_data (blob, &data_len); + + if (!data || !data_len) + goto fail; + + if (hb_blob_is_gzip (data, data_len)) + { + uint32_t expected_size = 0; + if (hb_gzip_get_uncompressed_size (data, data_len, &expected_size) && + unlikely ((size_t) expected_size > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)) + goto fail; + + hb_blob_t *uncompressed = hb_blob_decompress_gzip (blob, + HB_SVG_MAX_DOCUMENT_SIZE); + if (!uncompressed) + goto fail; + + hb_blob_destroy (blob); + blob = uncompressed; + data = hb_blob_get_data (blob, &data_len); + if (!data || !data_len) + goto fail; + } + + if (unlikely ((size_t) data_len > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)) + goto fail; + + if (svg) *svg = data; + if (len) *len = data_len; + return blob; + +fail: + hb_blob_destroy (blob); + if (svg) *svg = nullptr; + if (len) *len = 0; + return nullptr; +} struct SVGDocumentIndexEntry { @@ -384,10 +430,12 @@ parse_cache_entries_linear (const char *svg, hb_vector_t *glyph_spans, hb_vector_t *id_entries) { - open_elem_t stack[MAX_DEPTH]; + open_elem_t stack[MAX_DEPTH] = {}; unsigned depth = 0; - defs_entries->alloc (256); - id_entries->alloc (256); + if (unlikely (!defs_entries->alloc (256) || + !glyph_spans->alloc (256) || + !id_entries->alloc (256))) + return false; unsigned defs_depth = 0; unsigned i = 0; @@ -470,30 +518,24 @@ parse_cache_entries_linear (const char *svg, if (e.id.len) { - auto *id_slot = id_entries->push (); - if (unlikely (!id_slot)) + if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))) return false; - *id_slot = {e.id, (uint32_t) e.start, (uint32_t) end}; if (e.in_defs_content) { - auto *slot = defs_entries->push (); - if (unlikely (!slot)) + if (unlikely (!defs_entries->push_or_fail ())) return false; - slot->id = e.id; - slot->start = e.start; - slot->end = end; + auto &slot = defs_entries->tail (); + slot.id = e.id; + slot.start = e.start; + slot.end = end; } hb_codepoint_t gid; if (parse_glyph_id_span (e.id, &gid)) { - auto *span = glyph_spans->push (); - if (unlikely (!span)) + if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))) return false; - span->glyph = gid; - span->start = (uint32_t) e.start; - span->end = (uint32_t) end; } } @@ -504,44 +546,42 @@ parse_cache_entries_linear (const char *svg, continue; } - SVG::svg_id_span_t id = {nullptr, 0}; + SVG::svg_id_span_t id = {}; parse_id_in_start_tag (svg, i, gt, &id); unsigned r = gt; while (r > i && isspace ((unsigned char) svg[r - 1])) r--; bool self_closing = (r > i && svg[r - 1] == '/'); - open_elem_t e = {i, id, defs_depth > 0, is_defs}; + open_elem_t e = {}; + e.start = i; + e.id = id; + e.in_defs_content = defs_depth > 0; + e.is_defs = is_defs; if (self_closing) { unsigned end = gt + 1; if (e.id.len) { - auto *id_slot = id_entries->push (); - if (unlikely (!id_slot)) + if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))) return false; - *id_slot = {e.id, (uint32_t) e.start, (uint32_t) end}; if (e.in_defs_content) { - auto *slot = defs_entries->push (); - if (unlikely (!slot)) + if (unlikely (!defs_entries->push_or_fail ())) return false; - slot->id = e.id; - slot->start = e.start; - slot->end = end; + auto &slot = defs_entries->tail (); + slot.id = e.id; + slot.start = e.start; + slot.end = end; } hb_codepoint_t gid; if (parse_glyph_id_span (e.id, &gid)) { - auto *span = glyph_spans->push (); - if (unlikely (!span)) + if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))) return false; - span->glyph = gid; - span->start = (uint32_t) e.start; - span->end = (uint32_t) end; } } } @@ -569,7 +609,7 @@ SVG::accelerator_t::accelerator_t (hb_face_t *face) doc_caches.init (); unsigned doc_count = table->get_document_count (); if (doc_count && unlikely (!doc_caches.resize (doc_count))) - doc_caches.resize (0); + doc_caches.clear (); for (unsigned i = 0; i < doc_caches.length; i++) doc_caches.arrayZ[i].set_relaxed (nullptr); } @@ -742,6 +782,8 @@ SVG::accelerator_t::doc_cache_get_glyph_span (const svg_doc_cache_t *doc, const auto &span = doc->glyph_spans.arrayZ[glyph - doc->start_glyph]; if (span.first == INVALID_SPAN) return false; + if (unlikely (span.first > span.second || span.second > doc->len)) + return false; if (start) *start = span.first; if (end) *end = span.second; @@ -759,6 +801,8 @@ SVG::accelerator_t::doc_cache_find_id_span (const svg_doc_cache_t *doc, hb_pair_t *span = nullptr; if (!doc->id_spans.has (id, &span)) return false; + if (unlikely (span->first > span->second || span->second > doc->len)) + return false; if (start) *start = span->first; if (end) *end = span->second; return true; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh index d0b8c1bd15..01d72b1297 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh @@ -616,7 +616,7 @@ struct GDEFVersion1_2 public: DEFINE_SIZE_MIN (4 + 4 * Types::size); - unsigned int get_size () const + size_t get_size () const { return min_size + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + @@ -755,7 +755,7 @@ struct GDEF ComponentGlyph = 4 }; - unsigned int get_size () const + size_t get_size () const { switch (u.version.major) { case 1: return u.version1.get_size (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh index 4d6d340520..3e2c15d566 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -51,7 +51,11 @@ struct EntryExitRecord }; static inline void -reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) +reverse_cursive_minor_offset (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction, + unsigned int new_parent) { int chain = pos[i].attach_chain(), type = pos[i].attach_type(); if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) @@ -61,18 +65,28 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc unsigned int j = (int) i + chain; + if (unlikely (j >= len)) + return; + /* Stop if we see new parent in the chain. */ if (j == new_parent) return; - reverse_cursive_minor_offset (pos, j, direction, new_parent); + int16_t reversed_chain = -chain; + /* The old edge was cleared above; if the reversed distance truncates, + * keep it detached instead of storing a poisoned chain. + */ + if (unlikely (reversed_chain != -chain)) + return; + + reverse_cursive_minor_offset (pos, len, j, direction, new_parent); if (HB_DIRECTION_IS_HORIZONTAL (direction)) pos[j].y_offset = -pos[i].y_offset; else pos[j].x_offset = -pos[i].x_offset; - pos[j].attach_chain() = -chain; + pos[j].attach_chain() = reversed_chain; pos[j].attach_type() = type; } @@ -228,7 +242,7 @@ struct CursivePosFormat1 * previous connection now attaches to new parent. Watch out for case * where new parent is on the path from old chain... */ - reverse_cursive_minor_offset (pos, child, c->direction, parent); + reverse_cursive_minor_offset (pos, buffer->len, child, c->direction, parent); pos[child].attach_chain() = (int) parent - (int) child; if (pos[child].attach_chain() != (int) parent - (int) child) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh index 5560fab174..46718ea7fe 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh @@ -24,11 +24,11 @@ struct PairSet : ValueBase public: DEFINE_SIZE_MIN (2); - static unsigned get_size (unsigned len1, unsigned len2) + static size_t get_size (unsigned len1, unsigned len2) { return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); } - static unsigned get_size (const ValueFormat valueFormats[2]) + static size_t get_size (const ValueFormat valueFormats[2]) { unsigned len1 = valueFormats[0].get_len (); unsigned len2 = valueFormats[1].get_len (); @@ -39,7 +39,7 @@ struct PairSet : ValueBase { const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* bytes */ + size_t stride; /* bytes */ }; bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh index 924fd78478..e231c4d2fc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh @@ -64,7 +64,7 @@ struct ValueFormat : HBUINT16 // be added to ValueFormat. As such, we use the faster hb_popcount8 // that only processes the lowest 8 bits. unsigned int get_len () const { return hb_popcount8 ((uint8_t) *this); } - unsigned int get_size () const { return get_len () * Value::static_size; } + size_t get_size () const { return get_len () * Value::static_size; } hb_vector_t get_device_table_indices () const { unsigned i = 0; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh index e2ec4a80e3..2d940c959e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh @@ -33,7 +33,7 @@ struct CompositeGlyphRecord }; public: - unsigned int get_size () const + size_t get_size () const { unsigned int size = min_size; /* glyphIndex is 24bit instead of 16bit */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh index 9f4a2bac5b..74c6509ece 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh @@ -186,6 +186,7 @@ struct SimpleGlyph /* One extra item at the end, for the instruction-count below. */ if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + if (unlikely (num_points < (unsigned) num_contours)) return false; unsigned old_length = points.length; points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh index 71989d8df4..a54587c878 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh @@ -121,7 +121,7 @@ struct glyf if (!use_short_loca) { - padded_offsets.resize (0); + padded_offsets.clear (); for (auto &g : glyphs) padded_offsets.push (g.length ()); } @@ -226,7 +226,7 @@ struct glyf_accelerator_t if (gid >= num_glyphs) return false; auto &all_points = scratch.all_points; - all_points.resize (0); + all_points.clear (); bool phantom_only = !consumer.is_consuming_contour_points (); if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh index 33de82d35b..c848b4c235 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh @@ -312,7 +312,7 @@ struct name { static constexpr hb_tag_t tableTag = HB_OT_TAG_name; - unsigned int get_size () const + size_t get_size () const { return min_size + count * nameRecordZ.item_size; } template { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -48,7 +48,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4 { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -114,7 +114,7 @@ struct ClassDef : public OT::ClassDef bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::ClassDef::min_size) return false; hb_barrier (); switch (u.format.v) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh index 46c703524d..5778ee9e1d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh @@ -36,7 +36,7 @@ static bool sanitize ( const OT::Layout::Common::CoverageFormat1_3* thiz, graph_t::vertex_t& vertex ) { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -47,7 +47,7 @@ static bool sanitize ( const OT::Layout::Common::CoverageFormat2_4* thiz, graph_t::vertex_t& vertex ) { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -158,7 +158,7 @@ struct Coverage : public OT::Layout::Common::Coverage bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; hb_barrier (); switch (u.format.v) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/graph.hh index af8b312580..54df655aa0 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/graph.hh @@ -814,6 +814,11 @@ struct graph_t if (unlikely (!check_success (!connected_roots.in_error ()))) break; unsigned next_space = this->next_space (); + if (next_space >= HB_REPACKER_MAX_SPACES) + { + check_success (false); + break; + } num_roots_for_space_.push (0); for (unsigned root : connected_roots) { @@ -1062,6 +1067,12 @@ struct graph_t */ unsigned duplicate (unsigned node_idx) { + if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + { + check_success (false); + return -1; + } + positions_invalid = true; distance_invalid = true; @@ -1221,6 +1232,12 @@ struct graph_t */ unsigned new_node (char* head, char* tail) { + if (vertices_.length >= HB_REPACKER_MAX_VERTICES) + { + check_success (false); + return -1; + } + positions_invalid = true; distance_invalid = true; @@ -1384,6 +1401,11 @@ struct graph_t void move_to_new_space (const hb_set_t& indices) { + if (num_roots_for_space_.length >= HB_REPACKER_MAX_SPACES) + { + check_success (false); + return; + } num_roots_for_space_.push (0); unsigned new_space = num_roots_for_space_.length - 1; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh index ea6bcd239a..73f4b15660 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh @@ -52,7 +52,7 @@ struct ExtensionFormat1 : public OT::ExtensionFormat1 bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; return vertex_len >= OT::ExtensionFormat1::static_size; } @@ -76,7 +76,7 @@ struct Lookup : public OT::Lookup bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Lookup::min_size) return false; hb_barrier (); return vertex_len >= this->get_size (); @@ -390,7 +390,7 @@ struct LookupList : public OT::LookupList { bool sanitize (const graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::LookupList::min_size) return false; hb_barrier (); return vertex_len >= OT::LookupList::item_size * this->len; @@ -424,7 +424,7 @@ struct GSTAR : public OT::GSUBGPOS bool sanitize (const graph_t::vertex_t& vertex) { - int64_t len = vertex.obj.tail - vertex.obj.head; + size_t len = vertex.obj.tail - vertex.obj.head; if (len < OT::GSUBGPOS::min_size) return false; hb_barrier (); return len >= get_size (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh index 8422712734..4ef78e53ec 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/ligature-graph.hh @@ -41,11 +41,11 @@ struct LigatureSet : public OT::Layout::GSUB_impl::LigatureSet { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < OT::Layout::GSUB_impl::LigatureSet::min_size) return false; hb_barrier (); - int64_t total_len = ligature.get_size() + OT::Layout::GSUB_impl::LigatureSet::min_size - ligature.len.get_size(); + size_t total_len = ligature.get_size() + OT::Layout::GSUB_impl::LigatureSet::min_size - ligature.len.get_size(); if (vertex_len < total_len) { return false; } @@ -57,7 +57,7 @@ struct LigatureSubstFormat1 : public OT::Layout::GSUB_impl::LigatureSubstFormat1 { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; unsigned min_size = OT::Layout::GSUB_impl::LigatureSubstFormat1_2::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -492,7 +492,7 @@ struct LigatureSubst : public OT::Layout::GSUB_impl::LigatureSubst bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh index 6d1a3d4ae4..a653f402ab 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh @@ -38,7 +38,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix { bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < AnchorMatrix::min_size) return false; hb_barrier (); @@ -126,7 +126,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray { bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; unsigned min_size = MarkArray::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -207,7 +207,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2= MarkBasePosFormat1::static_size; } @@ -430,7 +430,6 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2baseCoverage), prime_id, base_coverage_id); - graph.duplicate (prime_id, base_coverage_id); auto mark_coverage = sc.c.graph.as_table (this_index, &markCoverage); @@ -493,7 +492,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh index 85950b6345..7c3b048195 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh @@ -39,7 +39,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; if (vertex_len < min_size) return false; hb_barrier (); @@ -422,7 +422,6 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4objidx = class_def_2_id; class_def_link->position = 10; graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false); - graph.duplicate (pair_pos_prime_id, class_def_2_id); return pair_pos_prime_id; } @@ -624,7 +623,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos bool sanitize (graph_t::vertex_t& vertex) const { - int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + size_t vertex_len = vertex.obj.tail - vertex.obj.head; if (vertex_len < u.format.v.get_size ()) return false; hb_barrier (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh index 37fac8909e..4f89f1011d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh @@ -108,7 +108,7 @@ inline bool will_overflow (graph_t& graph, hb_vector_t* overflows = nullptr) { - if (overflows) overflows->resize (0); + if (overflows) overflows->clear (); graph.update_positions (); hb_hashmap_t record_set; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh index b63e791629..cec42c54f0 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh @@ -1266,8 +1266,7 @@ struct StateTableDriver next_state == StateTableT::STATE_START_OF_TEXT && start_state_safe_to_break_eot && is_not_actionable && - is_not_epsilon_transition && - !last_range; + is_not_epsilon_transition; if (is_null_transition) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh index 471bd187b9..7ff003f715 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh @@ -861,7 +861,7 @@ struct KerxSubTable { friend struct kerx; - unsigned int get_size () const { return u.header.length; } + size_t get_size () const { return u.header.length; } unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; } template diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh index c25833cf28..c56bdb7c7a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh @@ -987,9 +987,16 @@ struct hb_aat_layout_chain_accelerator_t { unsigned count = chain.get_subtable_count (); - unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) - - HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) + - count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t); + unsigned product; + if (unlikely (hb_unsigned_mul_overflows (count, + sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), &product))) + return nullptr; + + unsigned size; + if (unlikely (hb_unsigned_add_overflows (sizeof (hb_aat_layout_chain_accelerator_t) - + HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t), product, &size))) { + return nullptr; + } /* The following is a calloc because when we are collecting subtables, * some of them might be invalid and hence not collect; as a result, @@ -1026,7 +1033,7 @@ struct ChainSubtable template friend struct Chain; - unsigned int get_size () const { return length; } + size_t get_size () const { return length; } unsigned int get_type () const { return coverage & 0xFF; } unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } @@ -1236,7 +1243,7 @@ struct Chain c->reverse_buffer (); } - unsigned int get_size () const { return length; } + size_t get_size () const { return length; } template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-algs.hh index 0a7bdfc938..d35a723f72 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-algs.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-algs.hh @@ -89,7 +89,16 @@ static inline constexpr uint32_t hb_uint32_swap (uint32_t v) { return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } template -struct __attribute__((packed)) hb_packed_t { Type v; }; +struct __attribute__((packed)) hb_packed_t +{ + hb_packed_t () = default; + constexpr hb_packed_t (Type V) : v (V) {} + operator Type () const { return v; } + hb_packed_t & operator = (Type V) { v = V; return *this; } + + private: + Type v; +}; #ifndef HB_FAST_NUM_ACCESS @@ -134,9 +143,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap16 (V); + *((hb_packed_t *) v) = __builtin_bswap16 (V); } #else : v {BE ? uint8_t ((V >> 8) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -147,9 +156,9 @@ struct HBInt { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint16_t) *((const hb_packed_t *) v) : - __builtin_bswap16 (((const hb_packed_t *) v)->v) + __builtin_bswap16 ((uint16_t) *((const hb_packed_t *) v)) ; #else return (BE ? (v[0] << 8) : (v[0] )) @@ -186,9 +195,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap32 (V); + *((hb_packed_t *) v) = __builtin_bswap32 (V); } #else : v {BE ? uint8_t ((V >> 24) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -200,9 +209,9 @@ struct HBInt constexpr operator Type () const { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint32_t) *((const hb_packed_t *) v) : - __builtin_bswap32 (((const hb_packed_t *) v)->v) + __builtin_bswap32 ((uint32_t) *((const hb_packed_t *) v)) ; #else return (BE ? (v[0] << 24) : (v[0] )) @@ -226,9 +235,9 @@ struct HBInt #if HB_FAST_NUM_ACCESS { if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - ((hb_packed_t *) v)->v = V; + *((hb_packed_t *) v) = V; else - ((hb_packed_t *) v)->v = __builtin_bswap64 (V); + *((hb_packed_t *) v) = __builtin_bswap64 (V); } #else : v {BE ? uint8_t ((V >> 56) & 0xFF) : uint8_t ((V ) & 0xFF), @@ -244,9 +253,9 @@ struct HBInt constexpr operator Type () const { #if HB_FAST_NUM_ACCESS return (BE == (__BYTE_ORDER == __BIG_ENDIAN)) ? - ((const hb_packed_t *) v)->v + (uint64_t) *((const hb_packed_t *) v) : - __builtin_bswap64 (((const hb_packed_t *) v)->v) + __builtin_bswap64 ((uint64_t) *((const hb_packed_t *) v)) ; #else return (BE ? (uint64_t (v[0]) << 56) : (uint64_t (v[0]) )) @@ -276,12 +285,12 @@ struct HBFloat { #if HB_FAST_NUM_ACCESS { - if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - { - ((hb_packed_t *) v)->v = V; - return; - } - } + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + { + *((hb_packed_t *) v) = V; + return; + } + } #endif union { @@ -289,7 +298,7 @@ struct HBFloat hb_packed_t i; } u = {{V}}; - const HBInt I = u.i.v; + const HBInt I = (IntType) u.i; for (unsigned i = 0; i < Bytes; i++) v[i] = I.v[i]; } @@ -297,10 +306,10 @@ struct HBFloat /* c++14 constexpr */ operator Type () const { #if HB_FAST_NUM_ACCESS - { - if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) - return ((const hb_packed_t *) v)->v; - } + { + if (BE == (__BYTE_ORDER == __BIG_ENDIAN)) + return (Type) *((const hb_packed_t *) v); + } #endif HBInt I; @@ -312,7 +321,7 @@ struct HBFloat hb_packed_t f; } u = {{I}}; - return u.f.v; + return (Type) u.f; } private: uint8_t v[Bytes]; }; @@ -1191,6 +1200,21 @@ hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *resu return (size > 0) && (count >= ((unsigned int) -1) / size); } +static inline bool +hb_unsigned_add_overflows (unsigned int a, unsigned int b, unsigned *result = nullptr) +{ +#if hb_has_builtin(__builtin_add_overflow) + unsigned stack_result; + if (!result) + result = &stack_result; + return __builtin_add_overflow (a, b, result); +#endif + + if (result) + *result = a + b; + return b > (unsigned int) -1 - a; +} + /* * Sort and search. @@ -1315,15 +1339,12 @@ static inline void sort_r_swap(char *__restrict a, char *__restrict b, /* swap a, b iff a>b */ /* a and b must not be equal! */ /* __restrict is same as restrict but better support on old machines */ -template +template static inline int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w, - int (*compar)(const void *_a, - const void *_b, - Ts... _ds), - Ts... ds) + Compar compar) { - if(compar(a, b, ds...) > 0) { + if(compar(a, b) > 0) { sort_r_swap(a, b, w); return 1; } @@ -1348,23 +1369,17 @@ static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb) /* Implement recursive quicksort ourselves */ /* Note: quicksort is not stable, equivalent values may be swapped */ -template +template static inline void sort_r_simple(void *base, size_t nel, size_t w, - int (*compar)(const void *_a, - const void *_b, - Ts... _ds), - Ts... ds) + Compar compar) { char *b = (char *)base, *end = b + nel*w; - /* for(size_t i=0; i b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {} + for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar); pj -= w) {} } } else @@ -1375,68 +1390,36 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, char *pl, *ple, *pr, *pre, *pivot; char *last = b+w*(nel-1), *tmp; - /* - Use median of second, middle and second-last items as pivot. - First and last may have been swapped with pivot and therefore be extreme - */ char *l[3]; l[0] = b + w; l[1] = b+w*(nel/2); l[2] = last - w; - /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */ - - if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } - if(compar(l[1],l[2],ds...) > 0) { + if(compar(l[0],l[1]) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } + if(compar(l[1],l[2]) > 0) { SORT_R_SWAP(l[1], l[2], tmp); - if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } + if(compar(l[0],l[1]) > 0) { SORT_R_SWAP(l[0], l[1], tmp); } } - /* swap mid value (l[1]), and last element to put pivot as last element */ if(l[1] != last) { sort_r_swap(l[1], last, w); } - /* - pl is the next item on the left to be compared to the pivot - pr is the last item on the right that was compared to the pivot - ple is the left position to put the next item that equals the pivot - ple is the last right position where we put an item that equals the pivot - v- end (beyond the array) - EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE. - ^- b ^- ple ^- pl ^- pr ^- pre ^- last (where the pivot is) - Pivot comparison key: - E = equal, L = less than, u = unknown, G = greater than, E = equal - */ pivot = last; ple = pl = b; pre = pr = last; - /* - Strategy: - Loop into the list from the left and right at the same time to find: - - an item on the left that is greater than the pivot - - an item on the right that is less than the pivot - Once found, they are swapped and the loop continues. - Meanwhile items that are equal to the pivot are moved to the edges of the - array. - */ while(pl < pr) { - /* Move left hand items which are equal to the pivot to the far left. - break when we find an item that is greater than the pivot */ for(; pl < pr; pl += w) { - cmp = compar(pl, pivot, ds...); + cmp = compar(pl, pivot); if(cmp > 0) { break; } else if(cmp == 0) { if(ple < pl) { sort_r_swap(ple, pl, w); } ple += w; } } - /* break if last batch of left hand items were equal to pivot */ if(pl >= pr) { break; } - /* Move right hand items which are equal to the pivot to the far right. - break when we find an item that is less than the pivot */ for(; pl < pr; ) { - pr -= w; /* Move right pointer onto an unprocessed item */ - cmp = compar(pr, pivot, ds...); + pr -= w; + cmp = compar(pr, pivot); if(cmp == 0) { pre -= w; if(pr < pre) { sort_r_swap(pr, pre, w); } @@ -1449,22 +1432,13 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w, } } - pl = pr; /* pr may have gone below pl */ + pl = pr; - /* - Now we need to go from: EEELLLGGGGEEEE - to: LLLEEEEEEEGGGG - Pivot comparison key: - E = equal, L = less than, u = unknown, G = greater than, E = equal - */ sort_r_swap_blocks(b, ple-b, pl-ple); sort_r_swap_blocks(pr, pre-pr, end-pre); - /*for(size_t i=0; i static inline void @@ -1713,4 +1673,51 @@ double solve_itp (func_t f, } +/* + * Scope guard: runs a callable at scope exit (RAII cleanup for + * non-HB-type resources — raw malloc'd buffers, paired init/end + * calls like inflateInit/inflateEnd, FT_Done_* handles, etc.). + * + * Prefer hb_unique_ptr_t etc. for HB types; this is + * for the long tail of cleanup that those wrappers don't cover. + * + * Usage: + * void *buf = hb_malloc (len); + * if (!buf) return false; + * HB_SCOPE_GUARD (hb_free (buf)); + * ... multiple fallible operations ... + * return true; // buf freed automatically on any return path + */ +template +struct hb_scope_guard_t +{ + explicit hb_scope_guard_t (F &&f) : f (std::move (f)), active (true) {} + hb_scope_guard_t (hb_scope_guard_t &&o) noexcept + : f (std::move (o.f)), active (o.active) { o.active = false; } + hb_scope_guard_t (const hb_scope_guard_t &) = delete; + hb_scope_guard_t &operator= (const hb_scope_guard_t &) = delete; + hb_scope_guard_t &operator= (hb_scope_guard_t &&) = delete; + ~hb_scope_guard_t () { if (active) f (); } + + /* Release: dismiss the guard so the cleanup does NOT run. Use + * when transferring ownership out of the scope. */ + void release () { active = false; } + + private: + F f; + bool active; +}; + +template +static inline hb_scope_guard_t hb_make_scope_guard (F &&f) +{ return hb_scope_guard_t (std::forward (f)); } + +#define HB_SCOPE_GUARD_NAME_(line) hb_scope_guard_##line +#define HB_SCOPE_GUARD_NAME(line) HB_SCOPE_GUARD_NAME_(line) +#define HB_SCOPE_GUARD(stmt) \ + auto HB_SCOPE_GUARD_NAME(__LINE__) = \ + hb_make_scope_guard ([&]() { stmt; }); \ + (void) HB_SCOPE_GUARD_NAME(__LINE__) + + #endif /* HB_ALGS_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-array.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-array.hh index b0fbe1b600..2799d84910 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-array.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-array.hh @@ -32,6 +32,8 @@ #include "hb-iter.hh" #include "hb-null.hh" +#include + template struct hb_sorted_array_t; @@ -219,26 +221,54 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> return false; } - hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) + hb_sorted_array_t qsort (int (*cmp)(const void*, const void*)) { - //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) - hb_qsort (arrayZ, length, this->get_item_size (), cmp_); + hb_qsort (arrayZ, length, this->get_item_size (), cmp); return hb_sorted_array_t (*this); } + /* std::sort wants a strict-weak `a < b` boolean, but our other + * qsort overload (and most existing call sites) follow the C + * qsort convention of returning negative / zero / positive ints. + * Adapt to either via overload resolution: bool passes through; + * any other arithmetic return type is treated as the int signed + * comparator. */ + template static bool _qsort_lt (T v) { return v < 0; } + static bool _qsort_lt (bool v) { return v; } + + template + hb_sorted_array_t qsort (Compar compar) + { + if (likely (length)) + std::sort (arrayZ, arrayZ + length, + [&] (const Type &a, const Type &b) + { return _qsort_lt (compar (a, b)); }); + return hb_sorted_array_t (*this); + } + + private: + template ::value)> + hb_sorted_array_t _qsort (hb_priority<1>) + { + return qsort ([] (const Type &a, const Type &b) { return Type::cmp (&a, &b) < 0; }); + } + hb_sorted_array_t _qsort (hb_priority<0>) + { + return qsort ((int(*)(const void*, const void*)) Type::cmp); + } + public: + hb_sorted_array_t qsort () { - //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); - if (likely (length)) - hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); - return hb_sorted_array_t (*this); + return _qsort (hb_prioritize); } /* * Other methods. */ - unsigned int get_size () const { return length * this->get_item_size (); } + size_t get_size () const { return length * this->get_item_size (); } /* * Reverse the order of items in this array in the range [start, end). diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh index f9c0e8870f..35aa9aa4e7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh @@ -115,7 +115,7 @@ struct hb_inc_bimap_t void clear () { forw_map.clear (); - back_map.resize (0); + back_map.clear (); } /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh index 05725048c2..7525e5a573 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh @@ -117,9 +117,15 @@ struct hb_bit_set_t void clear () { - resize (0); - if (likely (successful)) - population = 0; + /* Early-out on already-empty. Protects the Null singleton + * (which is zero-initialized) from any writes. Any non-empty + * instance is a real heap object with writable storage, so + * clearing through the vector's always-safe clear() is fine + * even if we entered error state. */ + if (!pages.length && !population) return; + pages.clear (); + page_map.clear (); + population = 0; } bool is_empty () const { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.cc index c363636d64..3c00808e49 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.cc @@ -615,6 +615,160 @@ hb_blob_create_from_file (const char *file_name) return likely (blob) ? blob : hb_blob_get_empty (); } +#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) +static hb_blob_t * +_hb_blob_try_mmap (const char *file_name) +{ + hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return nullptr; + auto file_guard = hb_make_scope_guard ([&]() { hb_free (file); }); + + int fd = open (file_name, O_RDONLY | O_BINARY, 0); + if (unlikely (fd == -1)) return nullptr; + auto fd_guard = hb_make_scope_guard ([&]() { close (fd); }); + + struct stat st; + if (unlikely (fstat (fd, &st) == -1)) return nullptr; + + file->length = (unsigned long) st.st_size; + +#ifdef _PATH_RSRCFORKSPEC + if (unlikely (file->length == 0)) + { + int rfd = _open_resource_fork (file_name, file); + if (rfd != -1) + { + close (fd); + fd = rfd; + } + } +#endif + + file->contents = (char *) mmap (nullptr, file->length, PROT_READ, + MAP_PRIVATE | MAP_NORESERVE, fd, 0); + if (unlikely (file->contents == MAP_FAILED)) return nullptr; + + file_guard.release (); + /* fd_guard closes fd on return (ownership ends after mmap). */ + return hb_blob_create_or_fail (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); +} +#elif defined(_WIN32) && !defined(HB_NO_MMAP) +static hb_blob_t * +_hb_blob_try_mmap (const char *file_name) +{ + hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); + if (unlikely (!file)) return nullptr; + auto file_guard = hb_make_scope_guard ([&]() { hb_free (file); }); + + unsigned int size = strlen (file_name) + 1; + wchar_t *wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); + if (unlikely (!wchar_file_name)) return nullptr; + + /* Assume file name is given in UTF-8 encoding */ + int conversion = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size); + if (conversion <= 0) + { + /* Conversion failed due to invalid UTF-8 characters, + Repeat conversion based on system code page */ + mbstowcs (wchar_file_name, file_name, size); + } + + HANDLE fd; +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + { + CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; + ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; + ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; + ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; + ceparams.lpSecurityAttributes = nullptr; + ceparams.hTemplateFile = nullptr; + fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, &ceparams); + } +#else + fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + nullptr); +#endif + hb_free (wchar_file_name); + + if (unlikely (fd == INVALID_HANDLE_VALUE)) return nullptr; + auto fd_guard = hb_make_scope_guard ([&]() { CloseHandle (fd); }); + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + { + LARGE_INTEGER length; + GetFileSizeEx (fd, &length); + file->length = length.LowPart; + file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); + } +#else + file->length = (unsigned long) GetFileSize (fd, nullptr); + file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); +#endif + if (unlikely (!file->mapping)) return nullptr; + +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); +#else + file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); +#endif + if (unlikely (!file->contents)) return nullptr; + + file_guard.release (); + /* fd_guard closes fd on return. */ + return hb_blob_create_or_fail (file->contents, file->length, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, + (hb_destroy_func_t) _hb_mapped_file_destroy); +} +#endif + +/* Read a file without knowing its size beforehand. Used as a fallback + * for systems without mmap or to read from pipes. */ +static hb_blob_t * +_hb_blob_read_file (const char *file_name) +{ + unsigned long len = 0, allocated = BUFSIZ * 16; + char *data = (char *) hb_malloc (allocated); + if (unlikely (!data)) return nullptr; + auto data_guard = hb_make_scope_guard ([&]() { hb_free (data); }); + + FILE *fp = fopen (file_name, "rb"); + if (unlikely (!fp)) return nullptr; + HB_SCOPE_GUARD (fclose (fp)); + + while (!feof (fp)) + { + if (allocated - len < BUFSIZ) + { + allocated *= 2; + /* Don't allocate and go more than ~536MB, our mmap reader still + can cover files like that but lets limit our fallback reader */ + if (unlikely (allocated > (2 << 28))) return nullptr; + char *new_data = (char *) hb_realloc (data, allocated); + if (unlikely (!new_data)) return nullptr; + data = new_data; + } + + unsigned long addition = fread (data + len, 1, allocated - len, fp); + + int err = ferror (fp); +#ifdef EINTR // armcc doesn't have it + if (unlikely (err == EINTR)) continue; +#endif + if (unlikely (err)) return nullptr; + + len += addition; + } + + data_guard.release (); + return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data, + (hb_destroy_func_t) hb_free); +} + /** * hb_blob_create_from_file_or_fail: * @file_name: A filename @@ -636,158 +790,10 @@ hb_blob_create_from_file_or_fail (const char *file_name) { /* Adopted from glib's gmappedfile.c with Matthias Clasen and Allison Lortie permission but changed a lot to suit our need. */ -#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) - hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return nullptr; - - int fd = open (file_name, O_RDONLY | O_BINARY, 0); - if (unlikely (fd == -1)) goto fail_without_close; - - struct stat st; - if (unlikely (fstat (fd, &st) == -1)) goto fail; - - file->length = (unsigned long) st.st_size; - -#ifdef _PATH_RSRCFORKSPEC - if (unlikely (file->length == 0)) - { - int rfd = _open_resource_fork (file_name, file); - if (rfd != -1) - { - close (fd); - fd = rfd; - } - } +#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP) + if (hb_blob_t *blob = _hb_blob_try_mmap (file_name)) + return blob; #endif - - file->contents = (char *) mmap (nullptr, file->length, PROT_READ, - MAP_PRIVATE | MAP_NORESERVE, fd, 0); - - if (unlikely (file->contents == MAP_FAILED)) goto fail; - - close (fd); - - return hb_blob_create_or_fail (file->contents, file->length, - HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, - (hb_destroy_func_t) _hb_mapped_file_destroy); - -fail: - close (fd); -fail_without_close: - hb_free (file); - -#elif defined(_WIN32) && !defined(HB_NO_MMAP) - hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return nullptr; - - HANDLE fd; - int conversion; - unsigned int size = strlen (file_name) + 1; - wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); - if (unlikely (!wchar_file_name)) goto fail_without_close; - - /* Assume file name is given in UTF-8 encoding */ - conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size); - if (conversion <= 0) - { - /* Conversion failed due to invalid UTF-8 characters, - Repeat conversion based on system code page */ - mbstowcs(wchar_file_name, file_name, size); - } -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - { - CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; - ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); - ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF; - ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000; - ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000; - ceparams.lpSecurityAttributes = nullptr; - ceparams.hTemplateFile = nullptr; - fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, - OPEN_EXISTING, &ceparams); - } -#else - fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, - nullptr); -#endif - hb_free (wchar_file_name); - - if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - { - LARGE_INTEGER length; - GetFileSizeEx (fd, &length); - file->length = length.LowPart; - file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr); - } -#else - file->length = (unsigned long) GetFileSize (fd, nullptr); - file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); -#endif - if (unlikely (!file->mapping)) goto fail; - -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) - file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); -#else - file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); -#endif - if (unlikely (!file->contents)) goto fail; - - CloseHandle (fd); - return hb_blob_create_or_fail (file->contents, file->length, - HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file, - (hb_destroy_func_t) _hb_mapped_file_destroy); - -fail: - CloseHandle (fd); -fail_without_close: - hb_free (file); - -#endif - - /* The following tries to read a file without knowing its size beforehand - It's used as a fallback for systems without mmap or to read from pipes */ - unsigned long len = 0, allocated = BUFSIZ * 16; - char *data = (char *) hb_malloc (allocated); - if (unlikely (!data)) return nullptr; - - FILE *fp = fopen (file_name, "rb"); - if (unlikely (!fp)) goto fread_fail_without_close; - - while (!feof (fp)) - { - if (allocated - len < BUFSIZ) - { - allocated *= 2; - /* Don't allocate and go more than ~536MB, our mmap reader still - can cover files like that but lets limit our fallback reader */ - if (unlikely (allocated > (2 << 28))) goto fread_fail; - char *new_data = (char *) hb_realloc (data, allocated); - if (unlikely (!new_data)) goto fread_fail; - data = new_data; - } - - unsigned long addition = fread (data + len, 1, allocated - len, fp); - - int err = ferror (fp); -#ifdef EINTR // armcc doesn't have it - if (unlikely (err == EINTR)) continue; -#endif - if (unlikely (err)) goto fread_fail; - - len += addition; - } - fclose (fp); - - return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data, - (hb_destroy_func_t) hb_free); - -fread_fail: - fclose (fp); -fread_fail_without_close: - hb_free (data); - return nullptr; + return _hb_blob_read_file (file_name); } #endif /* !HB_NO_OPEN */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.hh index 7d28c161f7..cd5254dcaa 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-blob.hh @@ -56,7 +56,8 @@ struct hb_blob_t void *new_user_data, hb_destroy_func_t new_destroy) { - destroy_user_data (); + if (new_data != data) + destroy_user_data (); data = new_data; length = new_length; mode = new_mode; @@ -81,6 +82,149 @@ struct hb_blob_t void *user_data = nullptr; hb_destroy_func_t destroy = nullptr; + + /* + * Blob-recycling helpers. + * + * Encoders that produce a sized byte buffer and wrap it as an + * hb_blob_t can amortize malloc/blob-allocation across repeated + * renders by handing the output blob back via a recycle slot. On + * the next encode these helpers reuse (or realloc) the buffer and + * the same hb_blob_t handle is returned, skipping malloc/free + * and blob-handle churn across glyph-by-glyph encoding loops. + * + * Blobs managed by this machinery are identified by the address + * of recycle_data_destroy. + */ + + struct recycle_data_t + { + char *buf; + unsigned capacity; + }; + + static inline void recycle_data_destroy (void *user_data) + { + auto *bd = (recycle_data_t *) user_data; + hb_free (bd->buf); + hb_free (bd); + } + + /* Acquire a buffer of at least @needed bytes. If @recycled is + * one of our blobs, reuse its buffer (or realloc it). + * *@out_capacity receives the actual capacity (>= @needed). + * *@out_replaced_buf is set to the recycled buf when realloc + * fails and a fresh buffer was allocated instead -- the caller + * must hb_free() that buf after recycle_finalize() runs. Returns + * nullptr on allocation failure. */ + static inline char * + recycle_acquire (hb_blob_t *recycled, + unsigned needed, + unsigned *out_capacity, + char **out_replaced_buf) + { + *out_replaced_buf = nullptr; + + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (bd->capacity >= needed) + { + *out_capacity = bd->capacity; + return bd->buf; + } + /* Grow with a 1.5x ramp to amortize repeated growth. */ + unsigned alloc_bytes = needed; + if (unlikely (hb_unsigned_add_overflows (needed, needed / 2, + &alloc_bytes))) + alloc_bytes = needed; + char *new_buf = (char *) hb_realloc (bd->buf, alloc_bytes); + if (new_buf) + { + bd->buf = new_buf; + bd->capacity = alloc_bytes; + *out_capacity = alloc_bytes; + return new_buf; + } + /* Realloc failed. Fall through to a fresh hb_malloc and stash + * the old buf for the caller to free after recycle_finalize. */ + *out_replaced_buf = bd->buf; + } + + char *buf = (char *) hb_malloc (needed); + if (unlikely (!buf)) + return nullptr; + *out_capacity = needed; + return buf; + } + + /* Wrap @buf (of @capacity, with @length used) into an hb_blob_t. + * If @recycled is one of our blobs, update and return it (cheap); + * otherwise create a new blob. Pass @replaced_recycled_buf from + * recycle_acquire(). */ + static inline hb_blob_t * + recycle_finalize (char *buf, + unsigned capacity, + unsigned length, + hb_blob_t *recycled, + char *replaced_recycled_buf) + { + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (replaced_recycled_buf && replaced_recycled_buf != buf) + hb_free (replaced_recycled_buf); + bd->buf = buf; + bd->capacity = capacity; + recycled->data = (const char *) buf; + recycled->length = length; + return recycled; + } + + /* No recycled blob to update -- create a fresh one with our + * destroy closure so the next recycle round can reuse it. */ + recycle_data_t *bd = (recycle_data_t *) hb_malloc (sizeof (*bd)); + if (unlikely (!bd)) + { + hb_free (buf); + return nullptr; + } + bd->buf = buf; + bd->capacity = capacity; + + return hb_blob_create ((const char *) buf, length, + HB_MEMORY_MODE_WRITABLE, + bd, recycle_data_destroy); + } + + /* Discard @buf returned by recycle_acquire without committing to + * a blob. Frees @buf if it was a fresh allocation; leaves any + * recycled buffer untouched. */ + static inline void + recycle_abort (char *buf, hb_blob_t *recycled) + { + if (!buf) return; + if (recycled && recycled->destroy == recycle_data_destroy) + { + auto *bd = (recycle_data_t *) recycled->user_data; + if (buf == bd->buf) return; /* owned by the recycled blob */ + } + hb_free (buf); + } + + /* Stash @blob in @slot as the recycled output for the next + * encode. Destroys any previously stashed blob. Safe to call + * with @blob = nullptr or the empty-singleton blob (treated as + * "drop"). */ + static inline void + recycle_stash (hb_blob_t **slot, hb_blob_t *blob) + { + hb_blob_destroy (*slot); + *slot = nullptr; + if (!blob || blob == hb_blob_get_empty ()) + return; + *slot = blob; + } }; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh index 75a1a11298..e57b6163c8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-json.hh" +#line 33 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { 0u, 0u, 9u, 34u, 97u, 121u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, @@ -597,12 +597,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 601 "hb-buffer-deserialize-json.hh" +#line 594 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 606 "hb-buffer-deserialize-json.hh" +#line 597 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -712,7 +712,7 @@ _resume: #line 56 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_unicode ())) return false; } break; -#line 716 "hb-buffer-deserialize-json.hh" +#line 689 "hb-buffer-deserialize-json.hh" } _again: diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-glyphs.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-glyphs.hh index 8c0353b3b2..8fc54b36c4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-glyphs.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-glyphs.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-glyphs.hh" +#line 33 "hb-buffer-deserialize-text-glyphs.hh" static const unsigned char _deserialize_text_glyphs_trans_keys[] = { 0u, 0u, 35u, 124u, 48u, 57u, 60u, 124u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 62u, 62u, @@ -389,12 +389,12 @@ _hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 393 "hb-buffer-deserialize-text-glyphs.hh" +#line 386 "hb-buffer-deserialize-text-glyphs.hh" { cs = deserialize_text_glyphs_start; } -#line 398 "hb-buffer-deserialize-text-glyphs.hh" +#line 389 "hb-buffer-deserialize-text-glyphs.hh" { int _slen; int _trans; @@ -552,7 +552,7 @@ _resume: return false; } break; -#line 556 "hb-buffer-deserialize-text-glyphs.hh" +#line 523 "hb-buffer-deserialize-text-glyphs.hh" } _again: @@ -573,7 +573,7 @@ _again: *end_ptr = p; } break; -#line 577 "hb-buffer-deserialize-text-glyphs.hh" +#line 542 "hb-buffer-deserialize-text-glyphs.hh" } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh index 26ec0b4225..0bb00c4c2e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh @@ -32,7 +32,7 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text-unicode.hh" +#line 33 "hb-buffer-deserialize-text-unicode.hh" static const unsigned char _deserialize_text_unicode_trans_keys[] = { 0u, 0u, 43u, 102u, 48u, 102u, 48u, 124u, 48u, 57u, 62u, 124u, 48u, 124u, 60u, 117u, 85u, 117u, 85u, 117u, 0 @@ -150,12 +150,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, hb_glyph_info_t info = {0}; const hb_glyph_position_t pos = {0}; -#line 154 "hb-buffer-deserialize-text-unicode.hh" +#line 147 "hb-buffer-deserialize-text-unicode.hh" { cs = deserialize_text_unicode_start; } -#line 159 "hb-buffer-deserialize-text-unicode.hh" +#line 150 "hb-buffer-deserialize-text-unicode.hh" { int _slen; int _trans; @@ -215,7 +215,7 @@ _resume: hb_memset (&info, 0, sizeof (info)); } break; -#line 219 "hb-buffer-deserialize-text-unicode.hh" +#line 203 "hb-buffer-deserialize-text-unicode.hh" } _again: @@ -238,7 +238,7 @@ _again: *end_ptr = p; } break; -#line 242 "hb-buffer-deserialize-text-unicode.hh" +#line 224 "hb-buffer-deserialize-text-unicode.hh" } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc index 1afb7aa5ed..923524d708 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc @@ -439,9 +439,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * A human-readable, plain text format. * The serialized glyphs will look something like: * - * ``` + * |[ * [uni0651=0@518,0+0|uni0628=0+1897] - * ``` + * ]| * * - The serialized glyphs are delimited with `[` and `]`. * - Glyphs are separated with `|` @@ -457,10 +457,10 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * A machine-readable, structured format. * The serialized glyphs will look something like: * - * ``` + * |[ * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0}, - * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}] - * ``` + * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}] + * ]| * * Each glyph is a JSON object, with the following properties: * - `g`: the glyph name or glyph index if @@ -552,9 +552,9 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * A human-readable, plain text format. * The serialized codepoints will look something like: * - * ``` + * |[ *   - * ``` + * ]| * * - Glyphs are separated with `|` * - Unicode codepoints are expressed as zero-padded four (or more) @@ -572,9 +572,9 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * * For example: * - * ``` + * |[ * [{u:1617,cl:0},{u:1576,cl:1}] - * ``` + * ]| * * Return value: * The number of serialized items. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc index e1ccd5b94e..4bcdd03983 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc @@ -101,9 +101,9 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, /* Check that breaking up shaping at safe-to-break is indeed safe. */ - hb_buffer_t *fragment = hb_buffer_create_similar (buffer); + hb_unique_ptr_t fragment (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (fragment, (hb_buffer_flags_t (hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY))); - hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_unique_ptr_t reconstruction (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); unsigned int num_glyphs; @@ -164,11 +164,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_append (fragment, text_buffer, text_start, text_end); if (!hb_shape_full (font, fragment, features, num_features, shapers) || fragment->successful) - { - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); return true; - } hb_buffer_append (reconstruction, fragment, 0, -1); start = end; @@ -193,9 +189,6 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, } } - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragment); - return ret; } @@ -238,11 +231,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, * the one from original buffer in step 1. */ - hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer), - hb_buffer_create_similar (buffer)}; + hb_unique_ptr_t fragments[2] { + hb_unique_ptr_t (hb_buffer_create_similar (buffer)), + hb_unique_ptr_t (hb_buffer_create_similar (buffer)), + }; hb_buffer_set_flags (fragments[0], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY))); hb_buffer_set_flags (fragments[1], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY))); - hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_unique_ptr_t reconstruction (hb_buffer_create_similar (buffer)); hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); hb_segment_properties_t props; hb_buffer_get_segment_properties (buffer, &props); @@ -308,17 +303,16 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, } bool ret = true; - hb_buffer_diff_flags_t diff; /* * Shape the two fragment streams. */ if (!hb_shape_full (font, fragments[0], features, num_features, shapers) || !fragments[0]->successful) - goto out; + return ret; if (!hb_shape_full (font, fragments[1], features, num_features, shapers) || !fragments[1]->successful) - goto out; + return ret; if (!forward) { @@ -363,7 +357,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, /* * Diff results. */ - diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); @@ -375,11 +369,6 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, } } -out: - hb_buffer_destroy (reconstruction); - hb_buffer_destroy (fragments[0]); - hb_buffer_destroy (fragments[1]); - return ret; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc index 3da6577bd1..45d5877bce 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc @@ -1813,6 +1813,9 @@ hb_buffer_add_utf (hb_buffer_t *buffer, if (item_length == -1) item_length = text_length - item_offset; + item_offset = hb_min (item_offset, (unsigned) text_length); + item_length = hb_clamp (item_length, 0, text_length - (int) item_offset); + if (unlikely (item_length < 0 || item_length > INT_MAX / 8 || !buffer->ensure (buffer->len + item_length * sizeof (T) / 4))) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc index daf72b03c8..f4edc9b16d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc @@ -30,6 +30,7 @@ #ifdef HAVE_CAIRO #include "hb-cairo-utils.hh" +#include "hb-paint.hh" /* Some routines in this file were ported from BlackRenderer by Black Foundry. * Used by permission to relicense to HarfBuzz license. @@ -198,79 +199,6 @@ _hb_cairo_paint_glyph_image (hb_cairo_context_t *c, return true; } -static void -_hb_cairo_reduce_anchors (float x0, float y0, - float x1, float y1, - float x2, float y2, - float *xx0, float *yy0, - float *xx1, float *yy1) -{ - float q1x, q1y, q2x, q2y; - float s; - float k; - - q2x = x2 - x0; - q2y = y2 - y0; - q1x = x1 - x0; - q1y = y1 - y0; - - s = q2x * q2x + q2y * q2y; - if (s < 0.000001f) - { - *xx0 = x0; *yy0 = y0; - *xx1 = x1; *yy1 = y1; - return; - } - - k = (q2x * q1x + q2y * q1y) / s; - *xx0 = x0; - *yy0 = y0; - *xx1 = x1 - k * q2x; - *yy1 = y1 - k * q2y; -} - -static int -_hb_cairo_cmp_color_stop (const void *p1, - const void *p2) -{ - const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1; - const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2; - - if (c1->offset < c2->offset) - return -1; - else if (c1->offset > c2->offset) - return 1; - else - return 0; -} - -static void -_hb_cairo_normalize_color_line (hb_color_stop_t *stops, - unsigned int len, - float *omin, - float *omax) -{ - float min, max; - - hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); - - min = max = stops[0].offset; - for (unsigned int i = 0; i < len; i++) - { - min = hb_min (min, stops[i].offset); - max = hb_max (max, stops[i].offset); - } - - if (min != max) - { - for (unsigned int i = 0; i < len; i++) - stops[i].offset = (stops[i].offset - min) / (max - min); - } - - *omin = min; - *omax = max; -} - static bool _hb_cairo_get_color_stops (hb_cairo_context_t *c, hb_color_line_t *color_line, @@ -278,13 +206,26 @@ _hb_cairo_get_color_stops (hb_cairo_context_t *c, hb_color_stop_t **stops) { unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); + bool allocated = false; + if (unlikely (!len)) + return false; if (len > *count) { *stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t)); - if (unlikely (!stops)) + if (unlikely (!*stops)) return false; + allocated = true; } hb_color_line_get_color_stops (color_line, 0, &len, *stops); + if (unlikely (!len)) + { + if (allocated) + { + hb_free (*stops); + *stops = nullptr; + } + return false; + } for (unsigned i = 0; i < len; i++) if ((*stops)[i].is_foreground) { @@ -322,9 +263,9 @@ _hb_cairo_paint_linear_gradient (hb_cairo_context_t *c, if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) return; - _hb_cairo_normalize_color_line (stops, len, &min, &max); + hb_paint_normalize_color_line (stops, len, &min, &max); - _hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1); + hb_paint_reduce_linear_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1); xxx0 = xx0 + min * (xx1 - xx0); yyy0 = yy0 + min * (yy1 - yy0); @@ -370,7 +311,7 @@ _hb_cairo_paint_radial_gradient (hb_cairo_context_t *c, if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) return; - _hb_cairo_normalize_color_line (stops, len, &min, &max); + hb_paint_normalize_color_line (stops, len, &min, &max); xx0 = x0 + min * (x1 - x0); yy0 = y0 + min * (y1 - y0); @@ -566,6 +507,35 @@ _hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius, } } +static inline hb_cairo_color_t +_hb_cairo_color_from_hb_color (hb_color_t c) +{ + return { + hb_color_get_red (c) / 255.f, + hb_color_get_green (c) / 255.f, + hb_color_get_blue (c) / 255.f, + hb_color_get_alpha (c) / 255.f, + }; +} + +struct _hb_cairo_sweep_patch_ctx { + float cx, cy, radius; + cairo_pattern_t *pattern; +}; + +static void +_hb_cairo_sweep_emit_patch (float a0, hb_color_t c0, + float a1, hb_color_t c1, + void *user_data) +{ + auto *ctx = (_hb_cairo_sweep_patch_ctx *) user_data; + hb_cairo_color_t cc0 = _hb_cairo_color_from_hb_color (c0); + hb_cairo_color_t cc1 = _hb_cairo_color_from_hb_color (c1); + _hb_cairo_add_sweep_gradient_patches1 (ctx->cx, ctx->cy, ctx->radius, + a0, &cc0, a1, &cc1, + ctx->pattern); +} + static void _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, unsigned int n_stops, @@ -576,252 +546,15 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, float end_angle, cairo_pattern_t *pattern) { - float angles_[PREALLOCATED_COLOR_STOPS]; - float *angles = angles_; - hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS]; - hb_cairo_color_t *colors = colors_; - hb_cairo_color_t color0, color1; + hb_paint_extend_t hb_extend = + extend == CAIRO_EXTEND_REPEAT ? HB_PAINT_EXTEND_REPEAT : + extend == CAIRO_EXTEND_REFLECT ? HB_PAINT_EXTEND_REFLECT : + HB_PAINT_EXTEND_PAD; - if (start_angle == end_angle) - { - if (extend == CAIRO_EXTEND_PAD) - { - hb_cairo_color_t c; - if (start_angle > 0) - { - c.r = hb_color_get_red (stops[0].color) / 255.; - c.g = hb_color_get_green (stops[0].color) / 255.; - c.b = hb_color_get_blue (stops[0].color) / 255.; - c.a = hb_color_get_alpha (stops[0].color) / 255.; - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - 0., &c, - start_angle, &c, - pattern); - } - if (end_angle < HB_2_PI) - { - c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.; - c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.; - c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.; - c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.; - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - end_angle, &c, - HB_2_PI, &c, - pattern); - } - } - return; - } - - assert (start_angle != end_angle); - - /* handle directions */ - if (end_angle < start_angle) - { - hb_swap (start_angle, end_angle); - - for (unsigned i = 0; i < n_stops - 1 - i; i++) - hb_swap (stops[i], stops[n_stops - 1 - i]); - for (unsigned i = 0; i < n_stops; i++) - stops[i].offset = 1 - stops[i].offset; - } - - if (n_stops > PREALLOCATED_COLOR_STOPS) - { - angles = (float *) hb_malloc (sizeof (float) * n_stops); - colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops); - if (unlikely (!angles || !colors)) - { - hb_free (angles); - hb_free (colors); - return; - } - } - - for (unsigned i = 0; i < n_stops; i++) - { - angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); - colors[i].r = hb_color_get_red (stops[i].color) / 255.; - colors[i].g = hb_color_get_green (stops[i].color) / 255.; - colors[i].b = hb_color_get_blue (stops[i].color) / 255.; - colors[i].a = hb_color_get_alpha (stops[i].color) / 255.; - } - - if (extend == CAIRO_EXTEND_PAD) - { - unsigned pos; - - color0 = colors[0]; - for (pos = 0; pos < n_stops; pos++) - { - if (angles[pos] >= 0) - { - if (pos > 0) - { - float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); - _hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0); - } - break; - } - } - if (pos == n_stops) - { - /* everything is below 0 */ - color0 = colors[n_stops-1]; - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - 0., &color0, - HB_2_PI, &color0, - pattern); - goto done; - } - - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - 0., &color0, - angles[pos], &colors[pos], - pattern); - - for (pos++; pos < n_stops; pos++) - { - if (angles[pos] <= HB_2_PI) - { - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - angles[pos - 1], &colors[pos-1], - angles[pos], &colors[pos], - pattern); - } - else - { - float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); - _hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1); - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - angles[pos - 1], &colors[pos - 1], - HB_2_PI, &color1, - pattern); - break; - } - } - - if (pos == n_stops) - { - /* everything is below 2*M_PI */ - color0 = colors[n_stops - 1]; - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - angles[n_stops - 1], &color0, - HB_2_PI, &color0, - pattern); - goto done; - } - } - else - { - int k; - float span; - - span = angles[n_stops - 1] - angles[0]; - if (!span) - goto done; - - k = 0; - if (angles[0] >= 0) - { - float ss = angles[0]; - while (ss > 0) - { - if (span > 0) - { - ss -= span; - k--; - } - else - { - ss += span; - k++; - } - } - } - else if (angles[0] < 0) - { - float ee = angles[n_stops - 1]; - while (ee < 0) - { - if (span > 0) - { - ee += span; - k++; - } - else - { - ee -= span; - k--; - } - } - } - - //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span); - span = fabsf (span); - - for (signed l = k; l < 1000; l++) - { - for (unsigned i = 1; i < n_stops; i++) - { - float a0, a1; - hb_cairo_color_t *c0, *c1; - - if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT)) - { - a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span; - a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; - c0 = &colors[n_stops - 1 - (i - 1)]; - c1 = &colors[n_stops - 1 - i]; - } - else - { - a0 = angles[i-1] + l * span; - a1 = angles[i] + l * span; - c0 = &colors[i-1]; - c1 = &colors[i]; - } - - if (a1 < 0) - continue; - if (a0 < 0) - { - hb_cairo_color_t color; - float f = (0 - a0)/(a1 - a0); - _hb_cairo_interpolate_colors (c0, c1, f, &color); - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - 0, &color, - a1, c1, - pattern); - } - else if (a1 >= HB_2_PI) - { - hb_cairo_color_t color; - float f = (HB_2_PI - a0)/(a1 - a0); - _hb_cairo_interpolate_colors (c0, c1, f, &color); - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - a0, c0, - HB_2_PI, &color, - pattern); - goto done; - } - else - { - _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, - a0, c0, - a1, c1, - pattern); - } - } - } - } - -done: - - if (angles != angles_) - hb_free (angles); - if (colors != colors_) - hb_free (colors); + _hb_cairo_sweep_patch_ctx ctx { cx, cy, radius, pattern }; + hb_paint_sweep_gradient_tiles (stops, n_stops, hb_extend, + start_angle, end_angle, + _hb_cairo_sweep_emit_patch, &ctx); } void @@ -844,7 +577,10 @@ _hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c, if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) return; - hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); + hb_array_t (stops, len) + .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { + return a.offset < b.offset; + }); cairo_clip_extents (cr, &x1, &y1, &x2, &y2); max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx)); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc index 23ebd6bfc3..ddb5d23dc8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc @@ -227,6 +227,33 @@ hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, cairo_clip (cr); } +static hb_draw_funcs_t * +hb_cairo_push_clip_path_start (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void **draw_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_new_path (cr); + *draw_data = cr; + return hb_cairo_draw_get_funcs (); +} + +static void +hb_cairo_push_clip_path_end (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_close_path (cr); + cairo_clip (cr); +} + static void hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED, void *paint_data, @@ -428,6 +455,8 @@ static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t< hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr); hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr); hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr); + hb_paint_funcs_set_push_clip_path_start_func (funcs, hb_cairo_push_clip_path_start, nullptr, nullptr); + hb_paint_funcs_set_push_clip_path_end_func (funcs, hb_cairo_push_clip_path_end, nullptr, nullptr); hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr); hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr); hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr); @@ -645,8 +674,12 @@ hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font, c.cr = cr; c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key); - if (!hb_font_paint_glyph_or_fail (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color)) - return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; + /* Synthesizing variant: mono glyphs render here too via the + * push_clip_glyph + foreground-fill fallback inside + * hb_font_paint_glyph. Callers that want the cheaper + * outline path for mono fonts set CAIRO_COLOR_MODE_NO_COLOR + * on the font options instead. */ + hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color); return CAIRO_STATUS_SUCCESS; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff-specializer.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff-specializer.hh index 5b4dce5d03..0d8d396790 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff-specializer.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff-specializer.hh @@ -134,7 +134,7 @@ generalize_commands (hb_vector_t &commands) } /* Replace commands with generalized result */ - commands.resize (0); + commands.clear (); for (unsigned i = 0; i < result.length; i++) commands.push (result[i]); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh index c44b024762..6a338b462b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh @@ -55,7 +55,7 @@ struct blend_arg_t : number_t void reset_blends () { numValues = valueIndex = 0; - deltas.shrink (0); + deltas.clear (); } unsigned int numValues; @@ -281,13 +281,14 @@ struct cff2_cs_opset_t : cs_opset_t, PAR k = env.get_region_count (); n = env.argStack.pop_uint (); /* copy the blend values into blend array of the default values */ - unsigned int start = env.argStack.get_count () - ((k+1) * n); - /* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */ - if (unlikely (start > env.argStack.get_count ())) + unsigned int count = env.argStack.get_count (); + unsigned int total; + if (unlikely (hb_unsigned_mul_overflows (k + 1, n, &total) || total > count)) { env.set_error (); return; } + unsigned int start = count - total; for (unsigned int i = 0; i < n; i++) { const hb_array_t blends = env.argStack.sub_array (start + n + (i * k), k); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-config.hh index c522eeea2e..62e0d2022e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-config.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-config.hh @@ -43,6 +43,7 @@ #ifdef HB_TINY #define HB_LEAN #define HB_MINI +#define HB_NO_SVG #define HB_OPTIMIZE_SIZE #define HB_OPTIMIZE_SIZE_MORE #define HB_MINIMIZE_MEMORY_USAGE @@ -60,9 +61,6 @@ #define HB_NO_BUFFER_SERIALIZE #define HB_NO_BUFFER_VERIFY #define HB_NO_BITMAP -#define HB_NO_CFF -#define HB_NO_COLOR -#define HB_NO_DRAW #define HB_NO_ERRNO #define HB_NO_FACE_COLLECT_UNICODES #define HB_NO_GETENV @@ -78,13 +76,17 @@ #define HB_NO_NAME #define HB_NO_OPEN #define HB_NO_OT_FONT_GLYPH_NAMES -#define HB_NO_OT_SHAPE_FRACTIONS -#define HB_NO_PAINT #define HB_NO_SETLOCALE #define HB_NO_STYLE -#define HB_NO_SUBSET_LAYOUT #define HB_NO_VERTICAL #define HB_NO_VAR + +#if !(defined(HB_HAS_CAIRO) || defined(HB_HAS_RASTER) || defined(HB_HAS_VECTOR) || defined(HB_HAS_GPU)) +#define HB_NO_COLOR +#define HB_NO_DRAW +#define HB_NO_PAINT +#endif + #endif #ifdef HB_MINI @@ -92,8 +94,6 @@ #define HB_NO_LEGACY #define HB_NO_BEYOND_64K #define HB_NO_CUBIC_GLYF -#define HB_NO_VAR_COMPOSITES -#define HB_NO_VAR_HVF #endif #ifdef __OPTIMIZE_SIZE__ @@ -135,16 +135,17 @@ #define HB_NO_OT_FONT_BITMAP #endif +#ifdef HB_NO_DRAW +#define HB_NO_CFF +#define HB_NO_OUTLINE +#define HB_NO_PAINT +#endif + #ifdef HB_NO_CFF #define HB_NO_OT_FONT_CFF #define HB_NO_SUBSET_CFF #endif -#ifdef HB_NO_DRAW -#define HB_NO_OUTLINE -#define HB_NO_PAINT -#endif - #ifdef HB_NO_LEGACY #define HB_NO_CMAP_LEGACY_SUBTABLES #define HB_NO_FALLBACK_SHAPE diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc index 939e620f3b..9f46928275 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext-font.cc @@ -409,6 +409,12 @@ hb_coretext_get_glyph_name (hb_font_t *font, if (!cf_name) return false; + if (!size) + { + CFRelease (cf_name); + return true; + } + CFIndex len = CFStringGetLength (cf_name); if (len > (CFIndex)size - 1) len = (CFIndex)size - 1; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc index 94b058828b..7466c5bc77 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc @@ -84,26 +84,27 @@ _hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED, CTFontRef ct_font = create_ct_font (cg_font, (CGFloat) HB_CORETEXT_DEFAULT_FONT_SIZE); auto arr = CTFontCopyAvailableTables (ct_font, kCTFontTableOptionNoOptions); + HB_SCOPE_GUARD (CFRelease (arr)); + HB_SCOPE_GUARD (CFRelease (ct_font)); unsigned population = (unsigned) CFArrayGetCount (arr); - unsigned end_offset; if (!table_count) - goto done; + return population; if (unlikely (start_offset >= population)) { *table_count = 0; - goto done; + return population; } - end_offset = start_offset + *table_count; + unsigned end_offset = start_offset + *table_count; if (unlikely (end_offset < start_offset)) { *table_count = 0; - goto done; + return population; } - end_offset= hb_min (end_offset, (unsigned) population); + end_offset = hb_min (end_offset, (unsigned) population); *table_count = end_offset - start_offset; for (unsigned i = start_offset; i < end_offset; i++) @@ -112,9 +113,6 @@ _hb_cg_get_table_tags (const hb_face_t *face HB_UNUSED, table_tags[i - start_offset] = tag; } -done: - CFRelease (arr); - CFRelease (ct_font); return population; } @@ -525,30 +523,29 @@ hb_coretext_font_create (CTFontRef ct_font) CFDictionaryRef variations = CTFontCopyVariation (ct_font); if (variations) { + HB_SCOPE_GUARD (CFRelease (variations)); + hb_vector_t vars; hb_vector_t keys; hb_vector_t values; CFIndex count = CFDictionaryGetCount (variations); - if (unlikely (!vars.alloc_exact (count) || !keys.resize_exact (count) || !values.resize_exact (count))) - goto done; - - // Fetch them one by one and collect in a vector of our own. - CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ); - for (CFIndex i = 0; i < count; i++) + if (likely (vars.alloc_exact (count) && keys.resize_exact (count) && values.resize_exact (count))) { - int tag; - float value; - CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag); - CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value); + // Fetch them one by one and collect in a vector of our own. + CFDictionaryGetKeysAndValues (variations, keys.arrayZ, values.arrayZ); + for (CFIndex i = 0; i < count; i++) + { + int tag; + float value; + CFNumberGetValue ((CFNumberRef) keys.arrayZ[i], kCFNumberIntType, &tag); + CFNumberGetValue ((CFNumberRef) values.arrayZ[i], kCFNumberFloatType, &value); - hb_variation_t var = {tag, value}; - vars.push (var); + hb_variation_t var = {tag, value}; + vars.push (var); + } + hb_font_set_variations (font, vars.arrayZ, vars.length); } - hb_font_set_variations (font, vars.arrayZ, vars.length); - -done: - CFRelease (variations); } /* Let there be dragons here... */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh index b6b5c8f781..238c84b3ad 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh @@ -138,52 +138,64 @@ struct vtable_t static constexpr auto get_user_data = _get_user_data; }; -#define HB_DEFINE_VTABLE(name) \ +#define HB_DEFINE_VTABLE(name, empty) \ template<> \ struct vtable \ : vtable_t {} -HB_DEFINE_VTABLE (buffer); -HB_DEFINE_VTABLE (blob); -HB_DEFINE_VTABLE (face); -HB_DEFINE_VTABLE (font); -HB_DEFINE_VTABLE (font_funcs); -HB_DEFINE_VTABLE (map); -HB_DEFINE_VTABLE (set); -HB_DEFINE_VTABLE (shape_plan); -HB_DEFINE_VTABLE (unicode_funcs); -HB_DEFINE_VTABLE (draw_funcs); -HB_DEFINE_VTABLE (paint_funcs); - -#undef HB_DEFINE_VTABLE +HB_DEFINE_VTABLE (buffer, &hb_buffer_get_empty); +HB_DEFINE_VTABLE (blob, &hb_blob_get_empty); +HB_DEFINE_VTABLE (face, &hb_face_get_empty); +HB_DEFINE_VTABLE (font, &hb_font_get_empty); +HB_DEFINE_VTABLE (font_funcs, &hb_font_funcs_get_empty); +HB_DEFINE_VTABLE (map, &hb_map_get_empty); +HB_DEFINE_VTABLE (set, &hb_set_get_empty); +HB_DEFINE_VTABLE (shape_plan, &hb_shape_plan_get_empty); +HB_DEFINE_VTABLE (unicode_funcs, &hb_unicode_funcs_get_empty); +HB_DEFINE_VTABLE (draw_funcs, &hb_draw_funcs_get_empty); +HB_DEFINE_VTABLE (paint_funcs, &hb_paint_funcs_get_empty); #ifdef HB_SUBSET_H -#define HB_DEFINE_VTABLE(name) \ - template<> \ - struct vtable \ - : vtable_t {} - - -HB_DEFINE_VTABLE (subset_input); -HB_DEFINE_VTABLE (subset_plan); - -#undef HB_DEFINE_VTABLE +HB_DEFINE_VTABLE (subset_input, nullptr); +HB_DEFINE_VTABLE (subset_plan, nullptr); #endif +#ifdef HB_RASTER_H + +HB_DEFINE_VTABLE (raster_image, nullptr); +HB_DEFINE_VTABLE (raster_draw, nullptr); +HB_DEFINE_VTABLE (raster_paint, nullptr); + +#endif + + +#ifdef HB_VECTOR_H + +HB_DEFINE_VTABLE (vector_draw, nullptr); +HB_DEFINE_VTABLE (vector_paint, nullptr); + +#endif + + +#ifdef HB_GPU_H + +HB_DEFINE_VTABLE (gpu_draw, nullptr); + +#endif + +/* HB_DEFINE_VTABLE stays available for subsystem headers' paired tail + * blocks (see hb-raster.h, hb-vector.h, hb-gpu.h, hb-subset.h). */ + + } // namespace hb /* Workaround for GCC < 7, see: diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.cc index 30ab86d33b..0997153f85 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.cc @@ -32,6 +32,8 @@ #include "hb-machinery.hh" +#include + /** * SECTION:hb-draw @@ -116,25 +118,25 @@ _hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !dfuncs->user_data) { dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); if (unlikely (!dfuncs->user_data)) - goto fail; + return false; } if (destroy && !dfuncs->destroy) { dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); if (unlikely (!dfuncs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_DRAW_FUNC_IMPLEMENT(name) \ @@ -460,6 +462,268 @@ hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, } +/** + * hb_draw_line: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @x0: start X coordinate + * @y0: start Y coordinate + * @w0: stroke width at the start + * @x1: end X coordinate + * @y1: end Y coordinate + * @w1: stroke width at the end + * @cap: end-cap shape (butt or square) + * + * Emits a tapered line segment as a filled trapezoid. @w0 and + * @w1 are the full stroke widths at the start and end points + * respectively; they may differ for a tapered stroke or match + * for a uniform one. Pass `NaN` for @w1 to use @w0 (uniform + * stroke) without repeating the value. + * + * With #HB_DRAW_LINE_CAP_SQUARE each endpoint is extended along + * the line direction by half its local stroke width, so four + * `hb_draw_line()` calls form a closed rectangle without gaps + * at the corners. + * + * Since: 14.2.0 + **/ +void +hb_draw_line (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x0, float y0, float w0, + float x1, float y1, float w1, + hb_draw_line_cap_t cap) +{ + if (std::isnan (w1)) w1 = w0; + float dx = x1 - x0, dy = y1 - y0; + float len = sqrtf (dx * dx + dy * dy); + if (len <= 0.f) + return; + /* Unit tangent and normal to the line direction. */ + float tx = dx / len; + float ty = dy / len; + float nx = -ty; + float ny = tx; + float h0 = 0.5f * w0; + float h1 = 0.5f * w1; + /* Square caps: extend each endpoint outward along the line + * tangent by half its local stroke width. */ + if (cap == HB_DRAW_LINE_CAP_SQUARE) + { + x0 -= tx * h0; y0 -= ty * h0; + x1 += tx * h1; y1 += ty * h1; + } + /* Trapezoid corners (counter-clockwise). */ + float ax = x0 + nx * h0, ay = y0 + ny * h0; + float bx = x1 + nx * h1, by = y1 + ny * h1; + float cx = x1 - nx * h1, cy = y1 - ny * h1; + float dx_ = x0 - nx * h0, dy_ = y0 - ny * h0; + + hb_draw_move_to (dfuncs, draw_data, st, ax, ay); + hb_draw_line_to (dfuncs, draw_data, st, bx, by); + hb_draw_line_to (dfuncs, draw_data, st, cx, cy); + hb_draw_line_to (dfuncs, draw_data, st, dx_, dy_); + hb_draw_close_path (dfuncs, draw_data, st); +} + +/* Emit an axis-aligned rectangle as a single closed contour. + * @ccw picks the winding direction (useful for cutting a hole + * out of another rectangle in a stroked rect). */ +static void +_hb_draw_rect_contour (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, float w, float h, + bool ccw) +{ + hb_draw_move_to (dfuncs, draw_data, st, x, y); + if (ccw) + { + hb_draw_line_to (dfuncs, draw_data, st, x + w, y); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x, y + h); + } + else + { + hb_draw_line_to (dfuncs, draw_data, st, x, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y + h); + hb_draw_line_to (dfuncs, draw_data, st, x + w, y); + } + hb_draw_close_path (dfuncs, draw_data, st); +} + +/** + * hb_draw_rectangle: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @x: top-left X coordinate + * @y: top-left Y coordinate + * @w: width (may be negative) + * @h: height (may be negative) + * @stroke_width: stroke width, or `NaN` for a filled rectangle + * + * Emits an axis-aligned rectangle. If @stroke_width is a finite + * positive value, the rectangle is rendered as an outlined ring + * of that thickness centered on the edges; if @stroke_width is + * `NaN`, the rectangle is rendered filled. + * + * Note: stroked rectangles produce a bounding box covering the + * full outer rectangle, so if the pen is a GPU fragment-shader + * backend, the shader runs for every interior pixel even though + * only the outline contributes coverage. For very thin + * outlines where the interior is much larger than the stroke, + * emitting four hb_draw_line() segments (one per edge) is + * considerably cheaper per frame. + * + * Since: 14.2.0 + **/ +void +hb_draw_rectangle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, + float w, float h, + float stroke_width) +{ + if (std::isnan (stroke_width)) + { + /* Filled rectangle with zero area is nothing to draw. */ + if (w == 0.f || h == 0.f) + return; + _hb_draw_rect_contour (dfuncs, draw_data, st, x, y, w, h, /*ccw*/ true); + return; + } + + if (stroke_width <= 0.f || !std::isfinite (stroke_width)) + return; + + /* Normalize to non-negative width/height so the stroke math + * below (outer grows by sw, inner shrinks by sw) produces the + * expected outer-contains-inner ring regardless of w/h signs. */ + if (w < 0.f) { x += w; w = -w; } + if (h < 0.f) { y += h; h = -h; } + /* w or h == 0 is still meaningful when stroking: a stroked + * zero-height rect is a horizontal line of length w; zero + * width is a vertical line. Both degenerate to a single + * outer contour because the inner hole collapses. */ + + /* Stroke is centered on the edge: outer contour grows by + * stroke_width/2, inner contour shrinks by the same. */ + float s = 0.5f * stroke_width; + /* Outer rectangle (CCW = adds coverage). */ + _hb_draw_rect_contour (dfuncs, draw_data, st, + x - s, y - s, + w + stroke_width, h + stroke_width, + /*ccw*/ true); + /* Inner rectangle (CW = removes coverage for the hole). */ + float iw = w - stroke_width; + float ih = h - stroke_width; + if (iw > 0.f && ih > 0.f) + _hb_draw_rect_contour (dfuncs, draw_data, st, + x + s, y + s, iw, ih, + /*ccw*/ false); +} + +/* Circle approximated by 4 cubic Beziers, one per quadrant. + * The magic constant 0.5522847498307936 is + * (4/3) * (sqrt(2) - 1) + * and minimizes the max radial error to ~2.7e-4 of r. */ +static void +_hb_draw_circle_contour (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, float r, + bool ccw) +{ + static const float k = 0.5522847498307936f; + float ck = r * k; + + hb_draw_move_to (dfuncs, draw_data, st, cx + r, cy); + if (ccw) + { + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + r, cy + ck, + cx + ck, cy + r, + cx, cy + r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - ck, cy + r, + cx - r, cy + ck, + cx - r, cy); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - r, cy - ck, + cx - ck, cy - r, + cx, cy - r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + ck, cy - r, + cx + r, cy - ck, + cx + r, cy); + } + else + { + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + r, cy - ck, + cx + ck, cy - r, + cx, cy - r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - ck, cy - r, + cx - r, cy - ck, + cx - r, cy); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx - r, cy + ck, + cx - ck, cy + r, + cx, cy + r); + hb_draw_cubic_to (dfuncs, draw_data, st, + cx + ck, cy + r, + cx + r, cy + ck, + cx + r, cy); + } + hb_draw_close_path (dfuncs, draw_data, st); +} + +/** + * hb_draw_circle: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @cx: center X coordinate + * @cy: center Y coordinate + * @r: radius + * @stroke_width: stroke width, or `NaN` for a filled disc + * + * Emits a circle approximated by four cubic Bezier curves. If + * @stroke_width is a finite positive value, the circle is + * rendered as an outlined ring of that thickness centered on + * the nominal radius; if @stroke_width is `NaN`, the circle is + * rendered as a filled disc. + * + * Since: 14.2.0 + **/ +void +hb_draw_circle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, + float r, + float stroke_width) +{ + if (r <= 0.f) + return; + + if (std::isnan (stroke_width)) + { + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, r, /*ccw*/ true); + return; + } + + if (stroke_width <= 0.f || !std::isfinite (stroke_width)) + return; + + float s = 0.5f * stroke_width; + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, r + s, /*ccw*/ true); + float ir = r - s; + if (ir > 0.f) + _hb_draw_circle_contour (dfuncs, draw_data, st, cx, cy, ir, /*ccw*/ false); +} + + static void hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, void *data, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.h index 76aa93f110..fe5a5c8614 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-draw.h @@ -335,6 +335,58 @@ hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st); +/* Shape helpers. + * + * Emit common primitives (tapered line, rectangle, circle) into + * any pen. The helpers are thin wrappers over the individual + * move_to / line_to / cubic_to / close_path calls: callers can + * always hand-roll the same shapes if they need a variation. + * + * For rect / circle the @stroke_width parameter selects between + * filled and stroked: a positive finite value is the stroke + * width of the outline; NaN means "filled" (no stroke). + */ + +/** + * hb_draw_line_cap_t: + * @HB_DRAW_LINE_CAP_BUTT: No cap; the line ends exactly at + * its endpoint. + * @HB_DRAW_LINE_CAP_SQUARE: Square cap; the line is extended + * past its endpoint by half the local stroke width. Useful + * for composing closed shapes from line segments (e.g. a + * rectangle made from four lines). + * + * End-cap shape for hb_draw_line(). + * + * Since: 14.2.0 + **/ +typedef enum { + HB_DRAW_LINE_CAP_BUTT = 0, + HB_DRAW_LINE_CAP_SQUARE = 1, +} hb_draw_line_cap_t; + +HB_EXTERN void +hb_draw_line (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x0, float y0, float w0, + float x1, float y1, float w1, + hb_draw_line_cap_t cap); + +HB_EXTERN void +hb_draw_rectangle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float x, float y, + float w, float h, + float stroke_width); + +HB_EXTERN void +hb_draw_circle (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float cx, float cy, + float r, + float stroke_width); + + HB_END_DECLS #endif /* HB_DRAW_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-face-builder.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-face-builder.cc index c3ddcd856b..d62bd9605f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-face-builder.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-face-builder.cc @@ -180,10 +180,8 @@ _hb_face_builder_get_table_tags (const hb_face_t *face HB_UNUSED, { // Not much to do... } - sorted_tags.qsort ([] (const void* a, const void* b) { - return * (hb_tag_t *) a < * (hb_tag_t *) b ? -1 : - * (hb_tag_t *) a == * (hb_tag_t *) b ? 0 : - +1; + sorted_tags.qsort ([] (const hb_tag_t &a, const hb_tag_t &b) { + return a < b; }); auto array = sorted_tags.as_array ().sub_array (start_offset, table_count); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.cc index fe94e2ea6c..96fcff5014 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.cc @@ -406,14 +406,15 @@ hb_font_get_glyph_h_origins_default (hb_font_t *font HB_UNUSED, { if (font->has_glyph_h_origin_func_set ()) { + hb_bool_t ret = true; for (unsigned int i = 0; i < count; i++) { - font->get_glyph_h_origin (*first_glyph, first_x, first_y, false); + ret &= font->get_glyph_h_origin (*first_glyph, first_x, first_y, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_x = &StructAtOffsetUnaligned (first_x, x_stride); first_y = &StructAtOffsetUnaligned (first_y, y_stride); } - return true; + return ret; } hb_bool_t ret = font->parent->get_glyph_h_origins (count, @@ -448,14 +449,15 @@ hb_font_get_glyph_v_origins_default (hb_font_t *font HB_UNUSED, { if (font->has_glyph_v_origin_func_set ()) { + hb_bool_t ret = true; for (unsigned int i = 0; i < count; i++) { - font->get_glyph_v_origin (*first_glyph, first_x, first_y, false); + ret &= font->get_glyph_v_origin (*first_glyph, first_x, first_y, false); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_x = &StructAtOffsetUnaligned (first_x, x_stride); first_y = &StructAtOffsetUnaligned (first_y, y_stride); } - return true; + return ret; } hb_bool_t ret = font->parent->get_glyph_v_origins (count, @@ -1001,25 +1003,25 @@ _hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !ffuncs->user_data) { ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); if (unlikely (!ffuncs->user_data)) - goto fail; + return false; } if (destroy && !ffuncs->destroy) { ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); if (unlikely (!ffuncs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_FONT_FUNC_IMPLEMENT(get_,name) \ @@ -1625,11 +1627,12 @@ hb_font_draw_glyph_or_fail (hb_font_t *font, * * Paints a color glyph. * - * This function is similar to, but lower-level than, - * hb_font_paint_glyph(). It is suitable for clients that - * need more control. If there are no color glyphs available, - * it will return `false`. The client can then fall back to - * hb_font_draw_glyph_or_fail() for the monochrome outline glyph. + * Succeeds if @glyph has color paint layers (COLRv0), + * a color paint graph (COLRv1), or a bitmap image that the + * font's callbacks render successfully. Returns `false` if + * the font has no color data for @glyph; the client can then + * fall back to hb_font_draw_glyph_or_fail() for the monochrome + * outline. * * The painting instructions are returned by way of calls to * the callbacks of the @funcs object, with @paint_data passed @@ -2414,6 +2417,10 @@ hb_font_set_parent (hb_font_t *font, if (!parent) parent = hb_font_get_empty (); + for (hb_font_t *p = parent; p && p != hb_font_get_empty(); p = p->parent) + if (p == font) + return; /* Would create a cycle - reject */ + hb_font_t *old = font->parent; font->parent = hb_font_reference (parent); @@ -3183,7 +3190,7 @@ hb_font_set_var_coords_design (hb_font_t *font, for (unsigned int i = input_coords_length; i < coords_length; i++) design_coords[i] = axes[i].get_default (); - hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.hh index 8d7bb2703c..842d0ea2d7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-font.hh @@ -172,13 +172,13 @@ struct hb_font_t /* Convert from parent-font user-space to our user-space */ hb_position_t parent_scale_x_distance (hb_position_t v) { - if (unlikely (parent && parent->x_scale != x_scale)) + if (unlikely (parent && parent->x_scale && parent->x_scale != x_scale)) return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale); return v; } hb_position_t parent_scale_y_distance (hb_position_t v) { - if (unlikely (parent && parent->y_scale != y_scale)) + if (unlikely (parent && parent->y_scale && parent->y_scale != y_scale)) return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale); return v; } @@ -903,15 +903,11 @@ struct hb_font_t } else { - for (unsigned j = 0; j < n; j++) - { - origins[j].x = 0; - origins[j].y = 0; - } + mult = 0; /* Indicates all origins[].x and origins[].y values are 0, therefore we can skip adjusting offsets below */ } } - assert (mult == -1 || mult == +1); + assert (mult == -1 || mult == +1 || mult == 0); if (mult == +1) for (unsigned j = 0; j < n; j++) { @@ -919,13 +915,14 @@ struct hb_font_t add_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } - else /* mult == -1 */ + else if (mult == -1) for (unsigned j = 0; j < n; j++) { hb_glyph_position_t *pos = &buf->pos[offset + j]; subtract_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } + /* else if (mult == 0) --> Do nothing */ offset += n; } @@ -970,15 +967,11 @@ struct hb_font_t } else { - for (unsigned j = 0; j < n; j++) - { - origins[j].x = 0; - origins[j].y = 0; - } + mult = 0; /* Indicates all origins[].x and origins[].y values are 0, therefore we can skip adjusting offsets below */ } } - assert (mult == -1 || mult == +1); + assert (mult == -1 || mult == +1 || mult == 0); if (mult == +1) for (unsigned j = 0; j < n; j++) { @@ -986,13 +979,14 @@ struct hb_font_t add_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } - else /* mult == -1 */ + else if (mult == -1) for (unsigned j = 0; j < n; j++) { hb_glyph_position_t *pos = &buf->pos[offset + j]; subtract_offset (&pos->x_offset, &pos->y_offset, origins[j].x, origins[j].y); } + /* else if (mult == 0) --> Do nothing */ offset += n; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ft.cc index 971f5078ee..8ac5db7746 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ft.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ft.cc @@ -766,6 +766,12 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + if (!size) + { + char buf[128]; + return !FT_Get_Glyph_Name (ft_face, glyph, buf, sizeof (buf)) && *buf; + } + hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); if (ret && (size && !*name)) ret = false; @@ -1117,14 +1123,13 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data buffer = (FT_Byte *) hb_malloc (length); if (!buffer) return nullptr; + auto buffer_guard = hb_make_scope_guard ([&]() { hb_free (buffer); }); error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); if (error) - { - hb_free (buffer); return nullptr; - } + buffer_guard.release (); return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free); @@ -1693,6 +1698,13 @@ _release_blob (void *arg) void hb_ft_font_set_funcs (hb_font_t *font) { + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + if (font->destroy == (hb_destroy_func_t) _hb_ft_font_destroy && font->user_data) + { + const hb_ft_font_t *existing_ft_font = (const hb_ft_font_t *) font->user_data; + load_flags = existing_ft_font->load_flags; + } + // In case of failure... hb_font_set_funcs (font, hb_font_funcs_get_empty (), @@ -1740,7 +1752,7 @@ hb_ft_font_set_funcs (hb_font_t *font) } _hb_ft_font_set_funcs (font, ft_face, true); - hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); + hb_ft_font_set_load_flags (font, load_flags); _hb_ft_hb_font_changed (font, ft_face); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc index 8e7589beac..e3b611cfbf 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-gdi.cc @@ -45,25 +45,25 @@ _hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_dat DWORD length = 0; HDC hdc = GetDC (nullptr); - if (unlikely (!SelectObject (hdc, (HFONT) user_data))) goto fail; + if (unlikely (!SelectObject (hdc, (HFONT) user_data))) + return hb_blob_get_empty (); + HB_SCOPE_GUARD (ReleaseDC (nullptr, hdc)); length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length); - if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc; + if (unlikely (length == GDI_ERROR)) + return hb_blob_get_empty (); buffer = (char *) hb_malloc (length); - if (unlikely (!buffer)) goto fail_with_releasedc; + if (unlikely (!buffer)) + return hb_blob_get_empty (); + auto buffer_guard = hb_make_scope_guard ([&]() { hb_free (buffer); }); + length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length); - if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free; - ReleaseDC (nullptr, hdc); + if (unlikely (length == GDI_ERROR)) + return hb_blob_get_empty (); + buffer_guard.release (); return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free); - -fail_with_releasedc_and_free: - hb_free (buffer); -fail_with_releasedc: - ReleaseDC (nullptr, hdc); -fail: - return hb_blob_get_empty (); } /** diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh index 60f4e692c0..ade9d8405a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-geometry.hh @@ -28,16 +28,25 @@ #include "hb-algs.hh" +#include + template struct hb_extents_t { hb_extents_t () {} - hb_extents_t (const hb_glyph_extents_t &extents) : - xmin (hb_min (extents.x_bearing, extents.x_bearing + extents.width)), - ymin (hb_min (extents.y_bearing, extents.y_bearing + extents.height)), - xmax (hb_max (extents.x_bearing, extents.x_bearing + extents.width)), - ymax (hb_max (extents.y_bearing, extents.y_bearing + extents.height)) {} + hb_extents_t (const hb_glyph_extents_t &extents) + { + double x0 = (double) extents.x_bearing; + double y0 = (double) extents.y_bearing; + double x1 = x0 + (double) extents.width; + double y1 = y0 + (double) extents.height; + + xmin = (Float) hb_min (x0, x1); + ymin = (Float) hb_min (y0, y1); + xmax = (Float) hb_max (x0, x1); + ymax = (Float) hb_max (y0, y1); + } hb_extents_t (Float xmin, Float ymin, Float xmax, Float ymax) : xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {} @@ -90,20 +99,37 @@ struct hb_extents_t hb_glyph_extents_t to_glyph_extents (bool xneg = false, bool yneg = false) const { - hb_position_t x0 = (hb_position_t) roundf (xmin); - hb_position_t y0 = (hb_position_t) roundf (ymin); - hb_position_t x1 = (hb_position_t) roundf (xmax); - hb_position_t y1 = (hb_position_t) roundf (ymax); - return hb_glyph_extents_t {xneg ? x1 : x0, - yneg ? y0 : y1, - xneg ? x0 - x1 : x1 - x0, - yneg ? y1 - y0 : y0 - y1}; + double x0 = round ((double) xmin); + double y0 = round ((double) ymin); + double x1 = round ((double) xmax); + double y1 = round ((double) ymax); + + if (unlikely (!std::isfinite (x0) || + !std::isfinite (y0) || + !std::isfinite (x1) || + !std::isfinite (y1))) + return hb_glyph_extents_t {0, 0, 0, 0}; + + return hb_glyph_extents_t { + clamp_to_hb_position (xneg ? x1 : x0), + clamp_to_hb_position (yneg ? y0 : y1), + clamp_to_hb_position (xneg ? x0 - x1 : x1 - x0), + clamp_to_hb_position (yneg ? y1 - y0 : y0 - y1) + }; } Float xmin = 0; Float ymin = 0; Float xmax = -1; Float ymax = -1; + + static hb_position_t + clamp_to_hb_position (double v) + { + return (hb_position_t) hb_clamp (v, + (double) hb_int_min (hb_position_t), + (double) hb_int_max (hb_position_t)); + } }; template diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc index e2acdffb1d..ed15725856 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc @@ -113,15 +113,11 @@ retry: hb_graphite2_face_data_t * _hb_graphite2_shaper_face_data_create (hb_face_t *face) { - hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF); + hb_unique_ptr_t silf_blob (face->reference_table (HB_GRAPHITE2_TAG_SILF)); /* Umm, we just reference the table to check whether it exists. * Maybe add better API for this? */ if (!hb_blob_get_length (silf_blob)) - { - hb_blob_destroy (silf_blob); return nullptr; - } - hb_blob_destroy (silf_blob); hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) hb_calloc (1, sizeof (hb_graphite2_face_data_t)); if (unlikely (!data)) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-limits.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-limits.hh index 857e183737..9d6c7ec682 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-limits.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-limits.hh @@ -108,5 +108,34 @@ #define HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH 64 #endif +#ifndef HB_SVG_MAX_PATH_SEGMENTS +#define HB_SVG_MAX_PATH_SEGMENTS 262144 +#endif + +#ifndef HB_GPU_DRAW_MAX_CURVES +#define HB_GPU_DRAW_MAX_CURVES 65536 +#endif + +#ifndef HB_SVG_MAX_DOCUMENT_SIZE +#define HB_SVG_MAX_DOCUMENT_SIZE ((size_t) 16 << 20) +#endif + +#ifndef HB_RASTER_MAX_BUFFER_SIZE +#define HB_RASTER_MAX_BUFFER_SIZE ((size_t) 1 << 30) +#endif + + +#ifndef HB_REPACKER_MAX_ITERATIONS +#define HB_REPACKER_MAX_ITERATIONS 500 +#endif + +#ifndef HB_REPACKER_MAX_VERTICES +#define HB_REPACKER_MAX_VERTICES 100000 +#endif + +#ifndef HB_REPACKER_MAX_SPACES +#define HB_REPACKER_MAX_SPACES 1024 +#endif + #endif /* HB_LIMITS_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh index 869fdba0ff..f3bb7fbf5b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh @@ -110,7 +110,7 @@ static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( #define DEFINE_SIZE_STATIC(size) \ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \ - unsigned int get_size () const { return (size); } \ + size_t get_size () const { return (size); } \ static constexpr unsigned null_size = (size); \ static constexpr unsigned min_size = (size); \ static constexpr unsigned static_size = (size) @@ -137,7 +137,7 @@ static inline auto StructAfter(TObject &X, Ts... args) HB_AUTO_RETURN(( static constexpr unsigned min_size = (size) #define DEFINE_SIZE_ARRAY_SIZED(size, array) \ - unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \ + size_t get_size () const { return (size - (array).min_size + (array).get_size ()); } \ DEFINE_SIZE_ARRAY(size, array) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-map.hh index fefdbb19de..37cc2460bb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-map.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-map.hh @@ -379,7 +379,11 @@ struct hb_hashmap_t void clear () { - if (unlikely (!successful)) return; + /* Early-out on already-empty. Protects the Null singleton + * (zero-initialized) from any writes. Any non-empty hashmap + * is a real heap instance with writable items, so clearing + * under !successful is safe. */ + if (!population && !occupancy) return; for (auto &_ : hb_iter (items, size ())) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh index 23a5c6f8b7..f50b39e6dc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ms-feature-ranges.hh @@ -86,8 +86,8 @@ hb_ms_setup_features (const hb_feature_t *features, hb_vector_t &feature_records, /* OUT */ hb_vector_t &range_records /* OUT */) { - feature_records.shrink(0); - range_records.shrink(0); + feature_records.clear (); + range_records.clear (); /* Sort features by start/end events. */ hb_vector_t feature_events; @@ -195,8 +195,8 @@ hb_ms_make_feature_ranges (hb_vector_t &feature_records, hb_vector_t &range_features, /* OUT */ hb_vector_t &range_counts /* OUT */) { - range_features.shrink (0); - range_counts.shrink (0); + range_features.clear (); + range_counts.clear (); auto *last_range = &range_records[0]; for (unsigned int i = chars_offset; i < chars_len; i++) @@ -213,8 +213,8 @@ hb_ms_make_feature_ranges (hb_vector_t &feature_records, auto *c = range_counts.push (); if (unlikely (!features || !c)) { - range_features.shrink (0); - range_counts.shrink (0); + range_features.clear (); + range_counts.clear (); break; } *features = &range->features; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh index 1a9dbba6dd..ec68c3a728 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh @@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ _resume: exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again: diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number.cc index c52b284e1d..926ef3b494 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-number.cc @@ -23,6 +23,10 @@ * */ +#ifndef HB_NUMBER_CC +#define HB_NUMBER_CC +#ifdef HB_NUMBER_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #include "hb-number.hh" #include "hb-number-parser.hh" @@ -77,3 +81,6 @@ hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer *pp = pend; return !whole_buffer || end == pend; } + +#endif /* HB_NUMBER_CC pacify */ +#endif /* HB_NUMBER_CC guard */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-object.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-object.hh index 7b34d671fb..3fb387978f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-object.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-object.hh @@ -272,6 +272,8 @@ static inline void hb_object_make_immutable (const Type *obj) obj->header.writable = false; } template +static inline void hb_object_fini (Type *obj); +template static inline Type *hb_object_reference (Type *obj) { hb_object_trace (obj, HB_FUNC); @@ -282,7 +284,7 @@ static inline Type *hb_object_reference (Type *obj) return obj; } template -static inline bool hb_object_destroy (Type *obj) +static inline bool hb_object_should_destroy (Type *obj) { hb_object_trace (obj, HB_FUNC); if (unlikely (!obj || obj->header.is_inert ())) @@ -290,12 +292,25 @@ static inline bool hb_object_destroy (Type *obj) assert (hb_object_is_valid (obj)); if (obj->header.ref_count.dec () != 1) return false; + return true; +} +template +static inline void hb_object_actually_destroy (Type *obj) +{ hb_object_fini (obj); if (!std::is_trivially_destructible::value) obj->~Type (); +} +template +static inline bool hb_object_destroy (Type *obj) +{ + if (!hb_object_should_destroy (obj)) + return false; + + hb_object_actually_destroy (obj); return true; } template diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh index e7c62cfe30..792101664f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh @@ -148,7 +148,7 @@ struct HBUINT15 : HBUINT16 /* 32-bit unsigned integer with variable encoding. */ struct HBUINT32VAR { - unsigned get_size () const + size_t get_size () const { unsigned b0 = v[0]; if (b0 < 0x80) @@ -163,7 +163,7 @@ struct HBUINT32VAR return 5; } - static unsigned get_size (uint32_t v) + static size_t get_size (uint32_t v) { if (v < 0x80) return 1; @@ -563,7 +563,7 @@ struct UnsizedArrayOf return arrayZ[i]; } - static unsigned int get_size (unsigned int len) + static size_t get_size (unsigned int len) { return len * Type::static_size; } template operator T * () { return arrayZ; } @@ -725,7 +725,7 @@ struct ArrayOf return arrayZ[i]; } - unsigned int get_size () const + size_t get_size () const { return len.static_size + len * Type::static_size; } explicit operator bool () const { return len; } @@ -909,7 +909,7 @@ struct HeadlessArrayOf hb_barrier (); return arrayZ[i-1]; } - unsigned int get_size () const + size_t get_size () const { return lenP1.static_size + get_length () * Type::static_size; } unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } @@ -1003,7 +1003,7 @@ struct ArrayOfM1 hb_barrier (); return arrayZ[i]; } - unsigned int get_size () const + size_t get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } template @@ -1197,7 +1197,7 @@ struct VarSizedBinSearchArrayOf } unsigned int get_length () const { return header.nUnits - last_is_terminator (); } - unsigned int get_size () const + size_t get_size () const { return header.static_size + header.nUnits * header.unitSize; } template @@ -1275,11 +1275,22 @@ struct CFFIndex if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false); unsigned char *ret = c->allocate_size (data_size, false); if (unlikely (!ret)) return_trace (false); + unsigned remaining = data_size; for (const auto &_ : +it) { unsigned len = _.length; + if (!len) continue; + + if (unlikely (len > remaining)) { + // We have more bytes to write then the computed data size, so the size calculation + // must have encountered overflow. + return_trace (c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + } + + remaining -= len; + if (len <= 1) { *ret++ = *_.arrayZ; @@ -1450,7 +1461,7 @@ struct CFFIndex return hb_ubytes_t (data_base () + offset0, offset1 - offset0); } - unsigned int get_size () const + size_t get_size () const { if (count) return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); @@ -2071,7 +2082,7 @@ struct TupleList : CFF2Index template struct Align { - unsigned get_size (const void *base) const + size_t get_size (const void *base) const { unsigned offset = (const char *) this - (const char *) base; return (alignment - offset) & (alignment - 1); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh index 4308a73442..1ee1f2874a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh @@ -201,7 +201,7 @@ struct FDSelect0 { hb_pair_t get_fd_range (hb_codepoint_t glyph) const { return {fds[glyph], glyph + 1}; } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } HBUINT8 fds[HB_VAR_ARRAY]; @@ -229,7 +229,7 @@ struct FDSelect3_4_Range template struct FDSelect3_4 { - unsigned int get_size () const + size_t get_size () const { return GID_TYPE::static_size * 2 + ranges.get_size (); } bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const @@ -304,7 +304,7 @@ struct FDSelect return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc index 8b666a3d0c..716e412f54 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc @@ -24,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#ifndef HB_OT_CFF1_TABLE_CC +#define HB_OT_CFF1_TABLE_CC +#ifdef HB_OT_CFF1_TABLE_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #ifndef HB_NO_CFF @@ -609,3 +613,6 @@ bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, #endif + +#endif /* HB_OT_CFF1_TABLE_CC pacify */ +#endif /* HB_OT_CFF1_TABLE_CC guard */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh index 66c375b2c6..5b2357e7e4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh @@ -234,7 +234,7 @@ struct Encoding return_trace (true); } - unsigned int get_size () const + size_t get_size () const { unsigned int size = min_size; switch (table_format ()) @@ -262,7 +262,7 @@ struct Encoding void get_supplement_codes (hb_codepoint_t sid, hb_vector_t &codes) const { - codes.resize (0); + codes.clear (); if (has_supplement ()) suppEncData().get_codes (sid, codes); } @@ -344,7 +344,7 @@ struct Charset0 return 0; } - static unsigned int get_size (unsigned int num_glyphs) + static size_t get_size (unsigned int num_glyphs) { assert (num_glyphs > 0); return UnsizedArrayOf::get_size (num_glyphs - 1); @@ -459,7 +459,7 @@ struct Charset1_2 { return 0; } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { int glyph = (int) num_glyphs; unsigned num_ranges = 0; @@ -475,7 +475,7 @@ struct Charset1_2 { return get_size_for_ranges (num_ranges); } - static unsigned int get_size_for_ranges (unsigned int num_ranges) + static size_t get_size_for_ranges (unsigned int num_ranges) { return UnsizedArrayOf >::get_size (num_ranges); } @@ -563,7 +563,7 @@ struct Charset return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc index bec1397ed5..92742ba63f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.cc @@ -24,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#ifndef HB_OT_CFF2_TABLE_CC +#define HB_OT_CFF2_TABLE_CC +#ifdef HB_OT_CFF2_TABLE_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #ifndef HB_NO_OT_FONT_CFF @@ -228,3 +232,6 @@ bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph } #endif + +#endif /* HB_OT_CFF2_TABLE_CC pacify */ +#endif /* HB_OT_CFF2_TABLE_CC guard */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh index 490077a67f..0618638354 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh @@ -58,7 +58,7 @@ struct CFF2FDSelect return_trace (true); } - unsigned int get_size (unsigned int num_glyphs) const + size_t get_size (unsigned int num_glyphs) const { switch (format) { @@ -130,7 +130,7 @@ struct CFF2ItemVariationStore return_trace (true); } - unsigned int get_size () const { return HBUINT16::static_size + size; } + size_t get_size () const { return HBUINT16::static_size + size; } HBUINT16 size; ItemVariationStore varStore; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-color.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-color.cc index 7f74a0f83a..34cdedb636 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-color.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-color.cc @@ -35,7 +35,9 @@ #include "OT/Color/COLR/COLR.hh" #include "OT/Color/CPAL/CPAL.hh" #include "OT/Color/sbix/sbix.hh" +#ifndef HB_NO_SVG #include "OT/Color/svg/svg.hh" +#endif /** @@ -274,6 +276,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, * SVG */ +#ifndef HB_NO_SVG /** * hb_ot_color_has_svg: * @face: #hb_face_t to work upon. @@ -372,6 +375,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) { return face->table.SVG->reference_blob_for_glyph (glyph); } +#endif /* diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh index afc8aa476e..9047b2880a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh @@ -140,8 +140,10 @@ HB_OT_ACCELERATOR (OT, COLR) HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) +#ifndef HB_NO_SVG HB_OT_ACCELERATOR (OT, SVG) #endif +#endif /* OpenType math. */ #ifndef HB_NO_MATH diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc index 76c4bf28d9..f42f679df2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc @@ -897,31 +897,29 @@ hb_ot_draw_glyph_or_fail (hb_font_t *font, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; hb_draw_session_t draw_session {draw_funcs, draw_data}; - bool ret = false; OT::hb_scalar_cache_t *gvar_cache = nullptr; +#ifndef HB_NO_VAR if (font->num_coords) { ot_font->check_serial (font); gvar_cache = ot_font->draw.acquire_gvar_cache (*ot_font->ot_face->gvar); } +#endif + HB_SCOPE_GUARD (ot_font->draw.release_gvar_cache (gvar_cache)); #ifndef HB_NO_VAR_COMPOSITES - if (font->face->table.VARC->get_path (font, glyph, draw_session)) { ret = true; goto done; } + if (font->face->table.VARC->get_path (font, glyph, draw_session)) return true; #endif // Keep the following in synch with VARC::get_path_at() - if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) { ret = true; goto done; } + if (font->face->table.glyf->get_path (font, glyph, draw_session, gvar_cache)) return true; #ifndef HB_NO_CFF - if (font->face->table.cff2->get_path (font, glyph, draw_session)) { ret = true; goto done; } - if (font->face->table.cff1->get_path (font, glyph, draw_session)) { ret = true; goto done; } + if (font->face->table.cff2->get_path (font, glyph, draw_session)) return true; + if (font->face->table.cff1->get_path (font, glyph, draw_session)) return true; #endif -done: - - ot_font->draw.release_gvar_cache (gvar_cache); - - return ret; + return false; } #endif @@ -937,7 +935,9 @@ hb_ot_paint_glyph_or_fail (hb_font_t *font, { #ifndef HB_NO_COLOR if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return true; +#ifndef HB_NO_SVG if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; +#endif #ifndef HB_NO_OT_FONT_BITMAP if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return true; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh index 5c187ebbb0..6ba918e2d7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh @@ -41,7 +41,7 @@ namespace OT { struct DeviceRecord { - static unsigned int get_size (unsigned count) + static size_t get_size (unsigned count) { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } template struct KernSubTable { - unsigned int get_size () const { return u.header.length; } + size_t get_size () const { return u.header.length; } unsigned int get_type () const { return u.header.format; } int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh index 0547301358..b07a400469 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh @@ -637,7 +637,7 @@ struct FeatureParamsCharacterVariants return characters.len; } - unsigned get_size () const + size_t get_size () const { return min_size + characters.len * HBUINT24::static_size; } void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const @@ -1272,7 +1272,7 @@ struct Lookup TSubTable& get_subtable (unsigned int i) { return this+get_subtables ()[i]; } - unsigned int get_size () const + size_t get_size () const { const HBUINT16 &markFilteringSet = StructAfter (subTable); if (lookupFlag & LookupFlag::UseMarkFilteringSet) @@ -2480,7 +2480,7 @@ struct VarRegionAxis /* TODO Move these to sanitize(). */ if (unlikely (start > peak || peak > end)) return 1.f; - if (unlikely (start < 0 && end > 0 && peak != 0)) + if (unlikely (start < 0 && end > 0)) return 1.f; if (coord <= start || end <= coord) @@ -2791,7 +2791,7 @@ struct VarRegionList return !regions.in_error (); } - unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } + size_t get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } public: HBUINT16 axisCount; @@ -2871,7 +2871,7 @@ struct VarData unsigned int get_row_size () const { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); } - unsigned int get_size () const + size_t get_size () const { return min_size - regionIndices.min_size + regionIndices.get_size () + itemCount * get_row_size (); @@ -2971,7 +2971,9 @@ struct VarData } if (unlikely (!c->extend_min (this))) return_trace (false); - itemCount = row_count; + if (unlikely (!c->check_assign (itemCount, row_count, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); int min_threshold = has_long ? -65536 : -128; int max_threshold = has_long ? +65535 : +127; @@ -3241,7 +3243,7 @@ struct VarData struct MultiVarData { - unsigned int get_size () const + size_t get_size () const { return min_size - regionIndices.min_size + regionIndices.get_size () + StructAfter (regionIndices).get_size (); @@ -3636,7 +3638,7 @@ struct DeltaSetIndexMapFormat01 { friend struct DeltaSetIndexMap; - unsigned get_size () const + size_t get_size () const { return min_size + mapCount * get_width (); } private: @@ -4802,7 +4804,7 @@ struct HintingDevice public: - unsigned int get_size () const + size_t get_size () const { unsigned int f = deltaFormat; if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh index 1f24376e72..df029ae79c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh @@ -1865,23 +1865,25 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, if (buffer->have_output) c->buffer->sync_so_far (); c->buffer->message (c->font, - "recursing to lookup %u at %u", + "start recursing to lookup %u at %u", (unsigned) lookupRecord[i].lookupListIndex, buffer->idx); } - if (!c->recurse (lookupRecord[i].lookupListIndex)) - continue; + bool ret = c->recurse (lookupRecord[i].lookupListIndex); if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { if (buffer->have_output) c->buffer->sync_so_far (); c->buffer->message (c->font, - "recursed to lookup %u", + "end recursing to lookup %u", (unsigned) lookupRecord[i].lookupListIndex); } + if (!ret) + continue; + unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); int delta = new_len - orig_len; @@ -4642,7 +4644,7 @@ struct GSUBGPOSVersion1_2 public: DEFINE_SIZE_MIN (4 + 3 * Types::size); - unsigned int get_size () const + size_t get_size () const { return min_size + (version.to_int () >= 0x00010001u ? featureVars.static_size : 0); @@ -4724,7 +4726,7 @@ struct GSUBGPOSVersion1_2 struct GSUBGPOS { - unsigned int get_size () const + size_t get_size () const { switch (u.version.major) { case 1: hb_barrier (); return u.version1.get_size (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc index f69274baec..c11d0e465c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc @@ -2072,21 +2072,25 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const { GSUBProxy proxy (font->face); + char tag[5] = {0}; + hb_tag_to_string (chosen_script[0], tag); if (buffer->messaging () && - !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return; + !buffer->message (font, "start table GSUB script tag '%s'", tag)) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0])); + (void) buffer->message (font, "end table GSUB script tag '%s'", tag); } void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const { GPOSProxy proxy (font->face); + char tag[5] = {0}; + hb_tag_to_string (chosen_script[0], tag); if (buffer->messaging () && - !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return; + !buffer->message (font, "start table GPOS script tag '%s'", tag)) return; apply (proxy, plan, font, buffer); if (buffer->messaging ()) - (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1])); + (void) buffer->message (font, "end table GPOS script tag '%s'", tag); } void diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh index c00d22b241..1ae0da1267 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh @@ -344,7 +344,7 @@ struct OS2 font_page_t get_font_page () const { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } - unsigned get_size () const + size_t get_size () const { unsigned result = min_size; if (version >= 1) result += v1X.get_size (); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh index 2d8acd825b..3741f13d03 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh @@ -194,7 +194,11 @@ struct post for (unsigned int i = 0; i < count; i++) gids[i] = i; - hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); + auto thiz = this; + hb_array_t (gids, count) + .qsort ([thiz] (const uint16_t &a, const uint16_t &b) { + return thiz->find_glyph_name (a).cmp (thiz->find_glyph_name (b)) > 0; + }); if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) { @@ -235,14 +239,6 @@ struct post return 0; } - static int cmp_gids (const void *pa, const void *pb, void *arg) - { - const accelerator_t *thiz = (const accelerator_t *) arg; - uint16_t a = * (const uint16_t *) pa; - uint16_t b = * (const uint16_t *) pb; - return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a)); - } - static int cmp_key (const void *pk, const void *po, void *arg) { const accelerator_t *thiz = (const accelerator_t *) arg; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc index e9dbcd77ae..e7007322e9 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc @@ -322,6 +322,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, /* First round, decompose */ bool all_simple = true; + if (buffer->message (font, "start decompose")) { buffer->clear_output (); count = buffer->len; @@ -364,6 +365,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, } while (buffer->idx < count && buffer->successful); buffer->sync (); + (void) buffer->message (font, "end decompose"); } @@ -420,7 +422,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, if (!all_simple && buffer->successful && (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS || - mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT)) + mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT) && + buffer->message (font, "start compose")) { /* As noted in the comment earlier, we don't try to combine * ccc=0 chars with their previous Starter. */ @@ -470,6 +473,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, starter = buffer->out_len - 1; } buffer->sync (); + (void) buffer->message (font, "end compose"); } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc index 7b3b854d57..c4027c4a78 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc @@ -1328,4 +1328,20 @@ hb_ot_shape_glyphs_closure (hb_font_t *font, } +/** + * hb_ot_shape_get_buffer_format_serial: + * + * Returns the serial number of the current internal buffer format. + * See #HB_OT_SHAPE_BUFFER_FORMAT_SERIAL for more information. + * + * Return value: The current buffer-format serial number. + * + * Since: 13.2.0 + **/ +unsigned int +hb_ot_shape_get_buffer_format_serial (void) +{ + return HB_OT_SHAPE_BUFFER_FORMAT_SERIAL; +} + #endif diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h index 80063f7751..48fbf843c1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h @@ -54,6 +54,21 @@ hb_ot_shape_plan_get_feature_tags (hb_shape_plan_t *shape_plan, unsigned int *tag_count, /* IN/OUT */ hb_tag_t *tags /* OUT */); +/** + * HB_OT_SHAPE_BUFFER_FORMAT_SERIAL: + * + * The serial number of the current internal buffer format. + * + * The serial number will increase when internal #hb_glyph_info_t and + * #hb_glyph_position_t members change their format. + * + * Since: 13.2.0 + */ +#define HB_OT_SHAPE_BUFFER_FORMAT_SERIAL 1 + +HB_EXTERN unsigned int +hb_ot_shape_get_buffer_format_serial (void); + HB_END_DECLS #endif /* HB_OT_SHAPE_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc index 69320eb954..d33b9099ec 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc @@ -561,20 +561,29 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed); DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating); - /* Number of additional times to repeat each repeating tile. */ - int n_copies = 0; + static constexpr unsigned STCH_MAX_GLYPHS = 256; - hb_position_t w_remaining = w_total - w_fixed; - if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0) - n_copies = (sign * w_remaining) / (sign * w_repeating) - 1; + /* Number of additional times to repeat each repeating tile. */ + unsigned int n_copies = 0; + + int64_t w_remaining_signed = (int64_t) w_total - w_fixed; + int64_t w_repeating_signed = w_repeating; + if (sign < 0) + { + w_remaining_signed = -w_remaining_signed; + w_repeating_signed = -w_repeating_signed; + } + hb_position_t w_remaining = (hb_position_t) (w_total - w_fixed); + if (w_remaining_signed > w_repeating_signed && w_repeating_signed > 0) + n_copies = w_remaining_signed / w_repeating_signed - 1; /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */ hb_position_t extra_repeat_overlap = 0; - hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1); + int64_t shortfall = w_remaining_signed - w_repeating_signed * (n_copies + 1); if (shortfall > 0 && n_repeating > 0) { ++n_copies; - hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining; + int64_t excess = (n_copies + 1) * w_repeating_signed - w_remaining_signed; if (excess > 0) { extra_repeat_overlap = excess / (n_copies * n_repeating); @@ -582,10 +591,25 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, } } + unsigned int max_copies = 0; + if (n_repeating > 0) + { + unsigned int base_glyphs = n_fixed + n_repeating; + if (base_glyphs < STCH_MAX_GLYPHS) + max_copies = (STCH_MAX_GLYPHS - base_glyphs) / n_repeating; + } + n_copies = hb_min (n_copies, max_copies); + if (step == MEASURE) { - extra_glyphs_needed += n_copies * n_repeating; - DEBUG_MSG (ARABIC, nullptr, "will add extra %d copies of repeating tiles", n_copies); + unsigned int added_glyphs = 0; + if (unlikely (hb_unsigned_mul_overflows (n_copies, n_repeating, &added_glyphs) || + hb_unsigned_add_overflows (extra_glyphs_needed, added_glyphs, &extra_glyphs_needed))) + { + extra_glyphs_needed = UINT_MAX; + break; + } + DEBUG_MSG (ARABIC, nullptr, "will add extra %u copies of repeating tiles", n_copies); } else { @@ -629,7 +653,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, if (step == MEASURE) { - if (unlikely (!buffer->ensure (count + extra_glyphs_needed))) + unsigned int total_glyphs = 0; + if (unlikely (hb_unsigned_add_overflows (count, extra_glyphs_needed, &total_glyphs) || + !buffer->ensure (total_glyphs))) break; } else diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh index 6ff65c30a3..92fb64ad07 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh @@ -53,7 +53,7 @@ enum indic_syllable_type_t { }; -#line 57 "hb-ot-shaper-indic-machine.hh" +#line 54 "hb-ot-shaper-indic-machine.hh" #define indic_syllable_machine_ex_A 9u #define indic_syllable_machine_ex_C 1u #define indic_syllable_machine_ex_CM 16u @@ -77,7 +77,7 @@ enum indic_syllable_type_t { #define indic_syllable_machine_ex_ZWNJ 5u -#line 81 "hb-ot-shaper-indic-machine.hh" +#line 76 "hb-ot-shaper-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { 8u, 57u, 4u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 8u, 57u, 5u, 57u, 5u, 57u, 13u, 13u, 4u, 57u, 4u, 57u, 4u, 57u, 4u, 57u, @@ -1126,7 +1126,7 @@ find_syllables_indic (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 1130 "hb-ot-shaper-indic-machine.hh" +#line 1119 "hb-ot-shaper-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -1142,7 +1142,7 @@ find_syllables_indic (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 1146 "hb-ot-shaper-indic-machine.hh" +#line 1131 "hb-ot-shaper-indic-machine.hh" { int _slen; int _trans; @@ -1156,7 +1156,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 1160 "hb-ot-shaper-indic-machine.hh" +#line 1143 "hb-ot-shaper-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1268,7 +1268,7 @@ _eof_trans: #line 117 "hb-ot-shaper-indic-machine.rl" {act = 7;} break; -#line 1272 "hb-ot-shaper-indic-machine.hh" +#line 1232 "hb-ot-shaper-indic-machine.hh" } _again: @@ -1277,7 +1277,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1281 "hb-ot-shaper-indic-machine.hh" +#line 1239 "hb-ot-shaper-indic-machine.hh" } if ( ++p != pe ) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc index e84b73eafd..74fe5efa3b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc @@ -77,9 +77,9 @@ static_assert (OT_VPst == M_Cat(VPst), ""); #define _OT_A OT_A /* 53 chars; A */ #define _OT_As OT_As /* 1 chars; As */ -#define _OT_C OT_C /* 478 chars; C */ +#define _OT_C OT_C /* 476 chars; C */ #define _OT_CM OT_CM /* 1 chars; CM */ -#define _OT_CS OT_CS /* 2 chars; CS */ +#define _OT_CS OT_CS /* 4 chars; CS */ #define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */ #define _OT_H OT_H /* 11 chars; H */ #define _OT_M OT_M /* 142 chars; M */ @@ -218,7 +218,7 @@ static const uint8_t _hb_indic_u8[1220]= 2, 24, 31, 35, 33, 34, 0, 32, 29, 9, 1, 21, 19, 20, 16, 2, 21, 21, 17, 2, 23, 2, 2, 35, 32, 2, 20, 35, 34, 32, 32, 29, 2, 29, 29, 32, 32, 35, 35, 34, 34, 34, 38, 39, 39, 26, 9, 39, - 27, 39, 0, 37, 0, 27, 27, 0, 0, 2, 2, 0, 41, 40, 5, 37, + 27, 39, 0, 37, 0, 27, 27, 0, 0, 4, 4, 0, 41, 40, 5, 37, 31, 12, 2, 23, }; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh index f1e7a91f05..848ed231f7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh @@ -48,7 +48,7 @@ enum khmer_syllable_type_t { }; -#line 52 "hb-ot-shaper-khmer-machine.hh" +#line 49 "hb-ot-shaper-khmer-machine.hh" #define khmer_syllable_machine_ex_C 1u #define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u #define khmer_syllable_machine_ex_H 4u @@ -66,7 +66,7 @@ enum khmer_syllable_type_t { #define khmer_syllable_machine_ex_ZWNJ 5u -#line 70 "hb-ot-shaper-khmer-machine.hh" +#line 65 "hb-ot-shaper-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, @@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 298 "hb-ot-shaper-khmer-machine.hh" +#line 287 "hb-ot-shaper-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 314 "hb-ot-shaper-khmer-machine.hh" +#line 299 "hb-ot-shaper-khmer-machine.hh" { int _slen; int _trans; @@ -324,7 +324,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 328 "hb-ot-shaper-khmer-machine.hh" +#line 311 "hb-ot-shaper-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -394,7 +394,7 @@ _eof_trans: #line 98 "hb-ot-shaper-khmer-machine.rl" {act = 3;} break; -#line 398 "hb-ot-shaper-khmer-machine.hh" +#line 368 "hb-ot-shaper-khmer-machine.hh" } _again: @@ -403,7 +403,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 407 "hb-ot-shaper-khmer-machine.hh" +#line 375 "hb-ot-shaper-khmer-machine.hh" } if ( ++p != pe ) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh index 4b8da586d3..292bc9f3df 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-myanmar-machine.hh @@ -50,7 +50,7 @@ enum myanmar_syllable_type_t { }; -#line 54 "hb-ot-shaper-myanmar-machine.hh" +#line 51 "hb-ot-shaper-myanmar-machine.hh" #define myanmar_syllable_machine_ex_A 9u #define myanmar_syllable_machine_ex_As 32u #define myanmar_syllable_machine_ex_C 1u @@ -78,7 +78,7 @@ enum myanmar_syllable_type_t { #define myanmar_syllable_machine_ex_ZWNJ 5u -#line 82 "hb-ot-shaper-myanmar-machine.hh" +#line 77 "hb-ot-shaper-myanmar-machine.hh" static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 57u, 3u, 57u, 5u, 57u, 5u, 57u, 3u, 57u, 5u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 3u, 57u, 5u, 57u, 1u, 15u, 3u, 57u, 3u, 57u, 3u, 57u, @@ -549,7 +549,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) int cs; hb_glyph_info_t *info = buffer->info; -#line 553 "hb-ot-shaper-myanmar-machine.hh" +#line 542 "hb-ot-shaper-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -565,7 +565,7 @@ find_syllables_myanmar (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 569 "hb-ot-shaper-myanmar-machine.hh" +#line 554 "hb-ot-shaper-myanmar-machine.hh" { int _slen; int _trans; @@ -579,7 +579,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 583 "hb-ot-shaper-myanmar-machine.hh" +#line 566 "hb-ot-shaper-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -649,7 +649,7 @@ _eof_trans: #line 113 "hb-ot-shaper-myanmar-machine.rl" {act = 3;} break; -#line 653 "hb-ot-shaper-myanmar-machine.hh" +#line 623 "hb-ot-shaper-myanmar-machine.hh" } _again: @@ -658,7 +658,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 662 "hb-ot-shaper-myanmar-machine.hh" +#line 630 "hb-ot-shaper-myanmar-machine.hh" } if ( ++p != pe ) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh index 65b6adc36d..5072e4d38e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh @@ -53,7 +53,7 @@ enum use_syllable_type_t { }; -#line 57 "hb-ot-shaper-use-machine.hh" +#line 54 "hb-ot-shaper-use-machine.hh" #define use_syllable_machine_ex_B 1u #define use_syllable_machine_ex_CGJ 6u #define use_syllable_machine_ex_CMAbv 31u @@ -100,7 +100,7 @@ enum use_syllable_type_t { #define use_syllable_machine_ex_ZWNJ 14u -#line 104 "hb-ot-shaper-use-machine.hh" +#line 99 "hb-ot-shaper-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { 49u, 51u, 0u, 56u, 11u, 56u, 11u, 56u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, @@ -929,7 +929,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int act HB_UNUSED; int cs; -#line 933 "hb-ot-shaper-use-machine.hh" +#line 922 "hb-ot-shaper-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -942,7 +942,7 @@ find_syllables_use (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 946 "hb-ot-shaper-use-machine.hh" +#line 931 "hb-ot-shaper-use-machine.hh" { int _slen; int _trans; @@ -956,7 +956,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 960 "hb-ot-shaper-use-machine.hh" +#line 943 "hb-ot-shaper-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -1078,7 +1078,7 @@ _eof_trans: #line 181 "hb-ot-shaper-use-machine.rl" {act = 9;} break; -#line 1082 "hb-ot-shaper-use-machine.hh" +#line 1039 "hb-ot-shaper-use-machine.hh" } _again: @@ -1087,7 +1087,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1091 "hb-ot-shaper-use-machine.hh" +#line 1046 "hb-ot-shaper-use-machine.hh" } if ( ++p != pe ) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh index 174816193e..f8a663b8ae 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh @@ -40,7 +40,7 @@ using rebase_tent_result_scratch_t = hb_pair_tcheck_struct (this)); } - unsigned get_size (unsigned axis_count_times_2) const + size_t get_size (unsigned axis_count_times_2) const { unsigned total_size = min_size; unsigned count = tupleVarCount.get_count (); @@ -1700,6 +1707,16 @@ struct item_variations_t const hb_map_t& get_varidx_map () const { return varidx_map; } + bool add_vardata_encoding_for_testing (hb_vector_t*> &&rows, + unsigned num_cols) + { + encodings.push (delta_row_encoding_t (std::move (rows), num_cols)); + return !encodings.in_error (); + } + + bool compile_varidx_map_for_testing (const hb_hashmap_t*>& front_mapping) + { return compile_varidx_map (front_mapping); } + bool instantiate (const ItemVariationStore& varStore, const hb_subset_plan_t *plan, bool optimize=true, @@ -2046,27 +2063,46 @@ struct item_variations_t { /* full encoding_row -> new VarIdxes mapping */ hb_hashmap_t*, unsigned> back_mapping; + hb_vector_t split_encodings; - for (unsigned major = 0; major < encodings.length; major++) + for (unsigned i = 0; i < encodings.length; i++) { - delta_row_encoding_t& encoding = encodings[major]; + delta_row_encoding_t& encoding = encodings[i]; /* just sanity check, this shouldn't happen */ if (encoding.is_empty ()) return false; unsigned num_rows = encoding.items.length; + unsigned num_cols = encoding.chars.length; /* sort rows, make result deterministic */ encoding.items.qsort (_cmp_row); - /* compile old to new var_idxes mapping */ - for (unsigned minor = 0; minor < num_rows; minor++) + for (unsigned start = 0; start < num_rows; start += 0xFFFFu) { - unsigned new_varidx = (major << 16) + minor; - back_mapping.set (encoding.items.arrayZ[minor], new_varidx); + unsigned chunk_len = hb_min (num_rows - start, 0xFFFFu); + hb_vector_t*> rows; + + if (!rows.alloc (chunk_len)) + return false; + + unsigned major = split_encodings.length; + for (unsigned minor = 0; minor < chunk_len; minor++) + { + const hb_vector_t *row = encoding.items.arrayZ[start + minor]; + rows.push (row); + if (!back_mapping.set (row, (major << 16) + minor)) + return false; + } + + split_encodings.push (delta_row_encoding_t (std::move (rows), num_cols)); } } + encodings = std::move (split_encodings); + if (encodings.in_error () || back_mapping.in_error ()) + return false; + for (auto _ : front_mapping.iter ()) { unsigned old_varidx = _.first; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh index a4959dbc43..349d6e2874 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh @@ -447,7 +447,7 @@ struct gvar_GVAR auto it = hb_iter (c->plan->new_to_old_gid_list); if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) it++; - unsigned int subset_data_size = 0; + size_t subset_data_size = 0; unsigned padding_size = 0; for (auto &_ : it) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh index ce1f9dcbaf..14ccdb7660 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh @@ -180,7 +180,7 @@ struct index_map_subset_plan_t unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); } unsigned int get_map_count () const { return map_count; } - unsigned int get_size () const + size_t get_size () const { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } bool is_identity () const { return get_output_map ().length == 0; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-outline.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-outline.hh index ed1057b8ac..9734583bfa 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-outline.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-outline.hh @@ -65,7 +65,7 @@ struct hb_outline_vector_t struct hb_outline_t { - void reset () { points.shrink (0, false); contours.resize (0); } + void reset () { points.clear (); contours.clear (); } HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const; HB_INTERNAL float control_area () const; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.cc index ffdd3c3a59..4565635a70 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.cc @@ -71,6 +71,15 @@ hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax, void *user_data) {} +static hb_draw_funcs_t * +hb_paint_push_clip_path_start_nil (hb_paint_funcs_t *funcs, void *paint_data, + void **draw_data, + void *user_data) { if (draw_data) *draw_data = nullptr; return nullptr; } + +static void +hb_paint_push_clip_path_end_nil (hb_paint_funcs_t *funcs, void *paint_data, + void *user_data) {} + static void hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data, void *user_data) {} @@ -118,6 +127,14 @@ static void hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data, void *user_data) {} +static void +hb_paint_push_group_for_nil (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data) +{ + hb_paint_push_group (funcs, paint_data); +} + static void hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode, @@ -158,25 +175,25 @@ _hb_paint_funcs_set_middle (hb_paint_funcs_t *funcs, void *user_data, hb_destroy_func_t destroy) { + auto destroy_guard = hb_make_scope_guard ([&]() { + if (destroy) destroy (user_data); + }); + if (user_data && !funcs->user_data) { funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data)); if (unlikely (!funcs->user_data)) - goto fail; + return false; } if (destroy && !funcs->destroy) { funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy)); if (unlikely (!funcs->destroy)) - goto fail; + return false; } + destroy_guard.release (); return true; - -fail: - if (destroy) - (destroy) (user_data); - return false; } #define HB_PAINT_FUNC_IMPLEMENT(name) \ @@ -573,6 +590,71 @@ hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data, funcs->push_clip_rectangle (paint_data, xmin, ymin, xmax, ymax); } +/** + * hb_paint_push_clip_path_start: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @draw_data: (out) (nullable): location to receive the draw data + * the caller should pass alongside the returned draw funcs. + * + * Begin clipping to an arbitrary path. Returns an + * #hb_draw_funcs_t owned by the backend (the caller must not + * free it) that the caller uses to emit the clip outline via + * hb_draw_*() calls, using the returned @draw_data as the + * draw data. The returned draw funcs and draw data are only + * valid until the matching hb_paint_push_clip_path_end() call; + * no other paint calls should be made between start and end + * except hb_draw_*() on the returned funcs. Finish the path + * with hb_paint_push_clip_path_end(); pop the clip later + * with hb_paint_pop_clip(). + * + * Usage: + * + * |[ + * hb_draw_funcs_t *df = hb_paint_push_clip_path_start (pf, pd, &dd); + * hb_draw_move_to (df, dd, NULL, ...); + * hb_draw_line_to (df, dd, NULL, ...); + * ... + * hb_draw_close_path (df, dd, NULL); + * hb_paint_push_clip_path_end (pf, pd); + * /* paint ops here are clipped to the emitted path */ + * hb_paint_pop_clip (pf, pd); + * ]| + * + * Return value: (transfer none): draw funcs that accumulate + * the clip path, or `NULL` if the backend does not implement + * arbitrary-path clipping. + * + * Since: 14.2.0 + */ +hb_draw_funcs_t * +hb_paint_push_clip_path_start (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data) +{ + void *scratch = nullptr; + if (!draw_data) draw_data = &scratch; + return funcs->push_clip_path_start (paint_data, draw_data); +} + +/** + * hb_paint_push_clip_path_end: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * + * Signal that the arbitrary-clip path started by + * hb_paint_push_clip_path_start() is fully drawn. The + * accumulated path now acts as a clip on the paint context + * until a matching hb_paint_pop_clip() call. + * + * Since: 14.2.0 + */ +void +hb_paint_push_clip_path_end (hb_paint_funcs_t *funcs, void *paint_data) +{ + funcs->push_clip_path_end (paint_data); +} + /** * hb_paint_pop_clip: * @funcs: paint functions @@ -723,6 +805,25 @@ hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data) funcs->push_group (paint_data); } +/** + * hb_paint_push_group_for: + * @funcs: paint functions + * @paint_data: associated data passed by the caller + * @mode: the compositing mode that will be used when the group is popped + * + * Perform a "push-group" paint operation, with the compositing + * mode known in advance. By default, this calls + * hb_paint_push_group(). + * + * Since: 14.2.0 + */ +void +hb_paint_push_group_for (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode) +{ + funcs->push_group_for (paint_data, mode); +} + /** * hb_paint_pop_group: * @funcs: paint functions @@ -761,4 +862,297 @@ hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, return funcs->custom_palette_color (paint_data, color_index, color); } + +/** + * hb_paint_reduce_linear_anchors: + * @x0: x coordinate of P0 (color stop 0). + * @y0: y coordinate of P0 (color stop 0). + * @x1: x coordinate of P1 (color stop 1). + * @y1: y coordinate of P1 (color stop 1). + * @x2: x coordinate of P2 (rotation reference). + * @y2: y coordinate of P2 (rotation reference). + * @xx0: (out): x coordinate of the resulting axis start. + * @yy0: (out): y coordinate of the resulting axis start. + * @xx1: (out): x coordinate of the resulting axis end. + * @yy1: (out): y coordinate of the resulting axis end. + * + * Reduces a COLRv1 linear gradient's 3-anchor spec (P0=color + * stop 0, P1=color stop 1, P2=rotation reference) to the + * 2-point axis (P0, P1') used by SVG / cairo / most software + * renderers. P1' is the foot of P1 on the line through P0 + * perpendicular to (P2 - P0); the resulting axis is the + * gradient's actual direction (perpendicular to the rotation + * line). Degenerate (P0 == P2) passes through unchanged. + * + * Since: 14.2.0 + **/ +void +hb_paint_reduce_linear_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1) +{ + float q2x = x2 - x0, q2y = y2 - y0; + float s = q2x * q2x + q2y * q2y; + if (s < 1e-6f) + { + *xx0 = x0; *yy0 = y0; + *xx1 = x1; *yy1 = y1; + return; + } + float q1x = x1 - x0, q1y = y1 - y0; + float k = (q2x * q1x + q2y * q1y) / s; + *xx0 = x0; + *yy0 = y0; + *xx1 = x1 - k * q2x; + *yy1 = y1 - k * q2y; +} + +/** + * hb_paint_normalize_color_line: + * @stops: (array length=len) (inout): color stops. + * @len: number of stops. + * @min: (out): original minimum offset. + * @max: (out): original maximum offset. + * + * Sorts @stops by offset and rescales offsets into [0, 1] in + * place. Writes the original (min, max) to @min / @max so the + * caller can shift the gradient geometry (axis endpoints for + * linear, centers+radii for radial, start+end angles for sweep) + * to keep the rendered gradient visually unchanged after the + * rescale. Empty input is safe: both out-parameters set to 0. + * + * Since: 14.2.0 + **/ +void +hb_paint_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *min, + float *max) +{ + if (unlikely (!len)) + { + *min = *max = 0.f; + return; + } + + hb_array_t (stops, len) + .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { + return a.offset < b.offset; + }); + + float mn = stops[0].offset, mx = stops[0].offset; + for (unsigned i = 1; i < len; i++) + { + mn = hb_min (mn, stops[i].offset); + mx = hb_max (mx, stops[i].offset); + } + if (mn != mx) + for (unsigned i = 0; i < len; i++) + stops[i].offset = (stops[i].offset - mn) / (mx - mn); + + *min = mn; + *max = mx; +} + +/** + * hb_paint_sweep_gradient_tiles: + * @stops: (array length=n_stops) (inout): color stops (sorted, offsets in [0,1]). + * @n_stops: number of stops. + * @extend: extend mode. + * @start_angle: sweep start angle, in radians. + * @end_angle: sweep end angle, in radians. + * @emit_patch: (scope call): callback invoked once per tile. + * @user_data: data passed to @emit_patch. + * + * Iterates the full 0..2π sweep produced by a color-stop list, + * invoking @emit_patch once per (start, end) angular segment. + * Handles #HB_PAINT_EXTEND_PAD, #HB_PAINT_EXTEND_REPEAT, and + * #HB_PAINT_EXTEND_REFLECT. Stops must be pre-sorted by + * offset; use hb_paint_normalize_color_line() first if they + * aren't. + * + * Since: 14.2.0 + **/ +void +hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, + unsigned int n_stops, + hb_paint_extend_t extend, + float start_angle, + float end_angle, + hb_paint_sweep_gradient_tile_func_t emit_patch, + void *user_data) +{ + if (!n_stops) return; + + if (start_angle == end_angle) + { + if (extend == HB_PAINT_EXTEND_PAD) + { + if (start_angle > 0.f) + emit_patch (0.f, stops[0].color, start_angle, stops[0].color, user_data); + if (end_angle < HB_2_PI) + emit_patch (end_angle, stops[n_stops - 1].color, HB_2_PI, stops[n_stops - 1].color, user_data); + } + return; + } + + if (end_angle < start_angle) + { + float tmp = start_angle; start_angle = end_angle; end_angle = tmp; + for (unsigned i = 0; i < n_stops - 1 - i; i++) + { + hb_color_stop_t t = stops[i]; + stops[i] = stops[n_stops - 1 - i]; + stops[n_stops - 1 - i] = t; + } + for (unsigned i = 0; i < n_stops; i++) + stops[i].offset = 1.f - stops[i].offset; + } + + /* Map stop offsets to angles. */ + float angles_buf[16]; + hb_color_t colors_buf[16]; + float *angles = angles_buf; + hb_color_t *colors = colors_buf; + bool dynamic = false; + + if (n_stops > 16) + { + angles = (float *) hb_malloc (sizeof (float) * n_stops); + colors = (hb_color_t *) hb_malloc (sizeof (hb_color_t) * n_stops); + if (!angles || !colors) + { + hb_free (angles); + hb_free (colors); + return; + } + dynamic = true; + } + + for (unsigned i = 0; i < n_stops; i++) + { + angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); + colors[i] = stops[i].color; + } + + if (extend == HB_PAINT_EXTEND_PAD) + { + unsigned pos; + hb_color_t color0 = colors[0]; + for (pos = 0; pos < n_stops; pos++) + { + if (angles[pos] >= 0) + { + if (pos > 0) + { + float f = (0.f - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + color0 = hb_color_lerp (colors[pos - 1], colors[pos], f); + } + break; + } + } + if (pos == n_stops) + { + color0 = colors[n_stops - 1]; + emit_patch (0.f, color0, HB_2_PI, color0, user_data); + goto done; + } + emit_patch (0.f, color0, angles[pos], colors[pos], user_data); + for (pos++; pos < n_stops; pos++) + { + if (angles[pos] <= HB_2_PI) + emit_patch (angles[pos - 1], colors[pos - 1], angles[pos], colors[pos], user_data); + else + { + float f = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + hb_color_t color1 = hb_color_lerp (colors[pos - 1], colors[pos], f); + emit_patch (angles[pos - 1], colors[pos - 1], HB_2_PI, color1, user_data); + break; + } + } + if (pos == n_stops) + { + color0 = colors[n_stops - 1]; + emit_patch (angles[n_stops - 1], color0, HB_2_PI, color0, user_data); + goto done; + } + } + else + { + float span = angles[n_stops - 1] - angles[0]; + if (fabsf (span) < 1e-6f) + goto done; + + int k = 0; + if (angles[0] >= 0) + { + float ss = angles[0]; + while (ss > 0) + { + if (span > 0) { ss -= span; k--; } + else { ss += span; k++; } + } + } + else + { + float ee = angles[n_stops - 1]; + while (ee < 0) + { + if (span > 0) { ee += span; k++; } + else { ee -= span; k--; } + } + } + + span = fabsf (span); + for (int l = k; l < 1000; l++) + { + for (unsigned i = 1; i < n_stops; i++) + { + float a0_l, a1_l; + hb_color_t col0, col1; + if ((l % 2 != 0) && (extend == HB_PAINT_EXTEND_REFLECT)) + { + a0_l = angles[0] + angles[n_stops - 1] - angles[n_stops - i] + l * span; + a1_l = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; + col0 = colors[n_stops - i]; + col1 = colors[n_stops - 1 - i]; + } + else + { + a0_l = angles[i - 1] + l * span; + a1_l = angles[i] + l * span; + col0 = colors[i - 1]; + col1 = colors[i]; + } + + if (a1_l < 0.f) continue; + if (a0_l < 0.f) + { + float f = (0.f - a0_l) / (a1_l - a0_l); + hb_color_t c = hb_color_lerp (col0, col1, f); + emit_patch (0.f, c, a1_l, col1, user_data); + } + else if (a1_l >= HB_2_PI) + { + float f = (HB_2_PI - a0_l) / (a1_l - a0_l); + hb_color_t c = hb_color_lerp (col0, col1, f); + emit_patch (a0_l, col0, HB_2_PI, c, user_data); + goto done; + } + else + emit_patch (a0_l, col0, a1_l, col1, user_data); + } + } + } + +done: + if (dynamic) + { + hb_free (angles); + hb_free (colors); + } +} + #endif diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.h index 787118c46a..9057e3b720 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.h @@ -30,6 +30,7 @@ #define HB_PAINT_H #include "hb-common.h" +#include "hb-draw.h" HB_BEGIN_DECLS @@ -212,6 +213,53 @@ typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs, float xmax, float ymax, void *user_data); +/** + * hb_paint_push_clip_path_start_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @draw_data: (out): location to store the draw data the caller should + * pass alongside the returned draw funcs. + * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_path_start_func() + * + * A virtual method for the #hb_paint_funcs_t to begin clipping + * to an arbitrary path. The backend returns an + * #hb_draw_funcs_t it owns (the caller must not free it) + * that the caller feeds the clip outline to via hb_draw_*() + * calls, plus a @draw_data value to pass alongside those + * calls. Both are only valid until the matching + * #hb_paint_push_clip_path_end_func_t call; no other paint + * calls should be made in between. The clip remains + * in effect until a later #hb_paint_pop_clip_func_t call. + * + * Return value: (transfer none): draw funcs that accumulate + * the clip path, or `NULL` if arbitrary-path clipping is not + * supported. + * + * Since: 14.2.0 + */ +typedef hb_draw_funcs_t * (*hb_paint_push_clip_path_start_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data, + void *user_data); + +/** + * hb_paint_push_clip_path_end_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @user_data: User data pointer passed to hb_paint_funcs_set_push_clip_path_end_func() + * + * A virtual method for the #hb_paint_funcs_t to close the + * clip path started by the #hb_paint_push_clip_path_start_func_t + * vfunc. The emitted path is now active as a clip; subsequent + * paint ops are masked by it until a matching + * #hb_paint_pop_clip_func_t call. + * + * Since: 14.2.0 + */ +typedef void (*hb_paint_push_clip_path_end_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + void *user_data); + /** * hb_paint_pop_clip_func_t: * @funcs: paint functions object @@ -219,8 +267,9 @@ typedef void (*hb_paint_push_clip_rectangle_func_t) (hb_paint_funcs_t *funcs, * @user_data: User data pointer passed to hb_paint_funcs_set_pop_clip_func() * * A virtual method for the #hb_paint_funcs_t to undo - * the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t - * or #hb_paint_funcs_push_clip_rectangle_func_t vfuncs. + * the effect of a prior call to the #hb_paint_funcs_push_clip_glyph_func_t, + * #hb_paint_funcs_push_clip_rectangle_func_t, or + * #hb_paint_funcs_push_clip_path_end_func_t vfuncs. * * Since: 7.0.0 */ @@ -239,6 +288,23 @@ typedef void (*hb_paint_pop_clip_func_t) (hb_paint_funcs_t *funcs, * A virtual method for the #hb_paint_funcs_t to paint a * color everywhere within the current clip. * + * When @is_foreground is true, this color originates from the + * foreground-color sentinel in the font's color data. The + * @color parameter still carries a fully resolved RGBA value + * (with any paint-tree alpha already applied), so backends + * that do not need to distinguish the foreground can simply + * use @color directly. + * + * Backends that defer foreground resolution (e.g. to honor a + * CSS `currentColor` or a runtime uniform) should substitute + * their own foreground RGB when @is_foreground is true, but + * must combine the alpha from @color with their foreground + * alpha, since it encodes additional modulation from the + * paint tree. For this mode to work correctly, the caller + * should pass a fully-opaque foreground color to + * hb_font_paint_glyph(), so that the alpha in @color + * reflects only the paint-tree contribution. + * * Since: 7.0.0 */ typedef void (*hb_paint_color_func_t) (hb_paint_funcs_t *funcs, @@ -322,6 +388,9 @@ typedef hb_bool_t (*hb_paint_image_func_t) (hb_paint_funcs_t *funcs, * Color lines typically have offsets ranging between 0 and 1, * but that is not required. * + * The @is_foreground and @color fields have the same semantics + * as in #hb_paint_color_func_t. + * * Note: despite @color being unpremultiplied here, interpolation in * gradients shall happen in premultiplied space. See the OpenType spec * [COLR](https://learn.microsoft.com/en-us/typography/opentype/spec/colr) @@ -660,6 +729,28 @@ typedef void (*hb_paint_push_group_func_t) (hb_paint_funcs_t *funcs, void *paint_data, void *user_data); +/** + * hb_paint_push_group_for_func_t: + * @funcs: paint functions object + * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() + * @mode: the compositing mode that will be used when the group is popped + * @user_data: User data pointer passed to hb_paint_funcs_set_push_group_for_func() + * + * A virtual method for the #hb_paint_funcs_t to use + * an intermediate surface for subsequent paint calls, + * with the compositing mode known in advance. + * + * This is like #hb_paint_push_group_func_t, but the + * compositing mode is provided at push time. By default + * this calls #hb_paint_push_group_func_t. + * + * Since: 14.2.0 + */ +typedef void (*hb_paint_push_group_for_func_t) (hb_paint_funcs_t *funcs, + void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data); + /** * hb_paint_pop_group_func_t: * @funcs: paint functions object @@ -797,6 +888,40 @@ hb_paint_funcs_set_push_clip_rectangle_func (hb_paint_funcs_t void *user_data, hb_destroy_func_t destroy); +/** + * hb_paint_funcs_set_push_clip_path_start_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-path-start callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-clip-path-start callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_clip_path_start_func (hb_paint_funcs_t *funcs, + hb_paint_push_clip_path_start_func_t func, + void *user_data, + hb_destroy_func_t destroy); + +/** + * hb_paint_funcs_set_push_clip_path_end_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-path-end callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-clip-path-end callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_clip_path_end_func (hb_paint_funcs_t *funcs, + hb_paint_push_clip_path_end_func_t func, + void *user_data, + hb_destroy_func_t destroy); + /** * hb_paint_funcs_set_pop_clip_func: * @funcs: A paint functions struct @@ -916,6 +1041,23 @@ hb_paint_funcs_set_push_group_func (hb_paint_funcs_t *funcs, void *user_data, hb_destroy_func_t destroy); +/** + * hb_paint_funcs_set_push_group_for_func: + * @funcs: A paint functions struct + * @func: (closure user_data) (destroy destroy) (scope notified): The push-group-for callback + * @user_data: Data to pass to @func + * @destroy: (nullable): Function to call when @user_data is no longer needed + * + * Sets the push-group-for callback on the paint functions struct. + * + * Since: 14.2.0 + */ +HB_EXTERN void +hb_paint_funcs_set_push_group_for_func (hb_paint_funcs_t *funcs, + hb_paint_push_group_for_func_t func, + void *user_data, + hb_destroy_func_t destroy); + /** * hb_paint_funcs_set_pop_group_func: * @funcs: A paint functions struct @@ -985,6 +1127,15 @@ hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data, float xmin, float ymin, float xmax, float ymax); +HB_EXTERN hb_draw_funcs_t * +hb_paint_push_clip_path_start (hb_paint_funcs_t *funcs, + void *paint_data, + void **draw_data); + +HB_EXTERN void +hb_paint_push_clip_path_end (hb_paint_funcs_t *funcs, + void *paint_data); + HB_EXTERN void hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data); @@ -1026,6 +1177,10 @@ hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data, HB_EXTERN void hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data); +HB_EXTERN void +hb_paint_push_group_for (hb_paint_funcs_t *funcs, void *paint_data, + hb_paint_composite_mode_t mode); + HB_EXTERN void hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_composite_mode_t mode); @@ -1035,6 +1190,58 @@ hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, unsigned int color_index, hb_color_t *color); + +/* + * Gradient helpers for paint backends. + * + * These are small, self-contained utilities that every COLRv1 + * renderer ends up reinventing. Exposed here so third-party + * paint backends can consume a single canonical implementation + * instead of forking one per project. + */ + +HB_EXTERN void +hb_paint_reduce_linear_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1); + +HB_EXTERN void +hb_paint_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *min, + float *max); + +/** + * hb_paint_sweep_gradient_tile_func_t: + * @a0: segment start angle, in radians. + * @c0: segment start color. + * @a1: segment end angle, in radians. + * @c1: segment end color. + * @user_data: user data passed to hb_paint_sweep_gradient_tiles(). + * + * Callback invoked once per (a0, a1) sector of a sweep + * gradient tiling. See hb_paint_sweep_gradient_tiles(). + * + * Since: 14.2.0 + **/ +typedef void (*hb_paint_sweep_gradient_tile_func_t) (float a0, + hb_color_t c0, + float a1, + hb_color_t c1, + void *user_data); + +HB_EXTERN void +hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, + unsigned int n_stops, + hb_paint_extend_t extend, + float start_angle, + float end_angle, + hb_paint_sweep_gradient_tile_func_t emit_patch, + void *user_data); + + HB_END_DECLS #endif /* HB_PAINT_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.hh index bbeeb0319d..148bfc974d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-paint.hh @@ -36,6 +36,8 @@ HB_PAINT_FUNC_IMPLEMENT (color_glyph) \ HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \ HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \ + HB_PAINT_FUNC_IMPLEMENT (push_clip_path_start) \ + HB_PAINT_FUNC_IMPLEMENT (push_clip_path_end) \ HB_PAINT_FUNC_IMPLEMENT (pop_clip) \ HB_PAINT_FUNC_IMPLEMENT (color) \ HB_PAINT_FUNC_IMPLEMENT (image) \ @@ -43,6 +45,7 @@ HB_PAINT_FUNC_IMPLEMENT (radial_gradient) \ HB_PAINT_FUNC_IMPLEMENT (sweep_gradient) \ HB_PAINT_FUNC_IMPLEMENT (push_group) \ + HB_PAINT_FUNC_IMPLEMENT (push_group_for) \ HB_PAINT_FUNC_IMPLEMENT (pop_group) \ HB_PAINT_FUNC_IMPLEMENT (custom_palette_color) \ /* ^--- Add new callbacks here */ @@ -102,6 +105,13 @@ struct hb_paint_funcs_t { func.push_clip_rectangle (this, paint_data, xmin, ymin, xmax, ymax, !user_data ? nullptr : user_data->push_clip_rectangle); } + hb_draw_funcs_t *push_clip_path_start (void *paint_data, + void **draw_data) + { return func.push_clip_path_start (this, paint_data, draw_data, + !user_data ? nullptr : user_data->push_clip_path_start); } + void push_clip_path_end (void *paint_data) + { func.push_clip_path_end (this, paint_data, + !user_data ? nullptr : user_data->push_clip_path_end); } void pop_clip (void *paint_data) { func.pop_clip (this, paint_data, !user_data ? nullptr : user_data->pop_clip); } @@ -146,6 +156,11 @@ struct hb_paint_funcs_t void push_group (void *paint_data) { func.push_group (this, paint_data, !user_data ? nullptr : user_data->push_group); } + void push_group_for (void *paint_data, + hb_paint_composite_mode_t mode) + { func.push_group_for (this, paint_data, + mode, + !user_data ? nullptr : user_data->push_group_for); } void pop_group (void *paint_data, hb_paint_composite_mode_t mode) { func.pop_group (this, paint_data, @@ -245,4 +260,17 @@ struct hb_paint_funcs_t DECLARE_NULL_INSTANCE (hb_paint_funcs_t); +/* Linearly interpolate between two hb_color_t values, component-wise, + * in byte-channel space with rounding. */ +static inline hb_color_t +hb_color_lerp (hb_color_t c0, hb_color_t c1, float t) +{ + auto lerp = [&] (unsigned shift) -> unsigned { + unsigned v0 = (c0 >> shift) & 0xFF; + unsigned v1 = (c1 >> shift) & 0xFF; + return (unsigned) (v0 + t * ((float) v1 - (float) v0) + 0.5f); + }; + return HB_COLOR (lerp (0), lerp (8), lerp (16), lerp (24)); +} + #endif /* HB_PAINT_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh index 753e86b8ca..8c32dabdd2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh @@ -61,7 +61,7 @@ struct hb_priority_queue_t bubble_down (i); } - void reset () { heap.resize (0); } + void reset () { heap.clear (); } bool in_error () const { return heap.in_error (); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-draw.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-draw.cc index c6a836a5ee..ba067561a2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-draw.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-draw.cc @@ -150,8 +150,11 @@ hb_raster_draw_reference (hb_raster_draw_t *draw) void hb_raster_draw_destroy (hb_raster_draw_t *draw) { - if (!hb_object_destroy (draw)) return; + if (!hb_object_should_destroy (draw)) + return; + hb_raster_image_destroy (draw->recycled_image); + hb_object_actually_destroy (draw); hb_free (draw); } @@ -193,7 +196,7 @@ hb_raster_draw_set_user_data (hb_raster_draw_t *draw, * Since: 13.0.0 **/ void * -hb_raster_draw_get_user_data (hb_raster_draw_t *draw, +hb_raster_draw_get_user_data (const hb_raster_draw_t *draw, hb_user_data_key_t *key) { return hb_object_get_user_data (draw, key); @@ -254,7 +257,7 @@ hb_raster_draw_set_scale_factor (hb_raster_draw_t *draw, * Since: 13.0.0 **/ void -hb_raster_draw_get_scale_factor (hb_raster_draw_t *draw, +hb_raster_draw_get_scale_factor (const hb_raster_draw_t *draw, float *x_scale_factor, float *y_scale_factor) { @@ -277,7 +280,7 @@ hb_raster_draw_get_scale_factor (hb_raster_draw_t *draw, * Since: 13.0.0 **/ void -hb_raster_draw_get_transform (hb_raster_draw_t *draw, +hb_raster_draw_get_transform (const hb_raster_draw_t *draw, float *xx, float *yx, float *xy, float *yy, float *dx, float *dy) @@ -321,7 +324,7 @@ hb_raster_draw_set_extents (hb_raster_draw_t *draw, * Since: 13.0.0 **/ hb_bool_t -hb_raster_draw_get_extents (hb_raster_draw_t *draw, +hb_raster_draw_get_extents (const hb_raster_draw_t *draw, hb_raster_extents_t *extents) { if (!draw->has_extents) @@ -401,6 +404,26 @@ hb_raster_draw_set_glyph_extents (hb_raster_draw_t *draw, return true; } +/** + * hb_raster_draw_clear: + * @draw: a rasterizer + * + * Discards accumulated geometry and extents so @draw can be reused + * for another render. User configuration (transform, scale factors) + * is preserved. Call hb_raster_draw_reset() to also reset user + * configuration to defaults. + * + * Since: 14.2.0 + **/ +void +hb_raster_draw_clear (hb_raster_draw_t *draw) +{ + draw->fixed_extents = {}; + draw->has_extents = false; + draw->edges.clear (); + draw->active_edges.clear (); +} + /** * hb_raster_draw_reset: * @draw: a rasterizer @@ -409,9 +432,6 @@ hb_raster_draw_set_glyph_extents (hb_raster_draw_t *draw, * geometry, the transform, and fixed extents. The object can then be * reused for a new glyph. * - * Internal scratch buffers and recycled image cache are preserved for - * reuse across subsequent renders. - * * Since: 13.0.0 **/ void @@ -420,10 +440,7 @@ hb_raster_draw_reset (hb_raster_draw_t *draw) draw->transform = {1, 0, 0, 1, 0, 0}; draw->x_scale_factor = 1.f; draw->y_scale_factor = 1.f; - draw->fixed_extents = {}; - draw->has_extents = false; - draw->edges.clear (); - draw->active_edges.clear (); + hb_raster_draw_clear (draw); } /** @@ -479,7 +496,8 @@ emit_segment (hb_raster_draw_t *draw, } else { e.xL = X1; e.yL = Y1; e.xH = X0; e.yH = Y0; e.wind = -1; } - e.slope = ((int64_t) (e.xH - e.xL) << 16) / (e.yH - e.yL); + e.slope = (((int64_t) e.xH - (int64_t) e.xL) * (int64_t) 65536) / + ((int64_t) e.yH - (int64_t) e.yL); draw->edges.push (e); } @@ -917,56 +935,68 @@ free_static_raster_draw_funcs () /** * hb_raster_draw_get_funcs: + * @draw: a rasterizer draw context. * - * Fetches the singleton #hb_draw_funcs_t that feeds outline data - * into an #hb_raster_draw_t. Pass the #hb_raster_draw_t as the - * @draw_data argument when calling the draw functions. + * Fetches the #hb_draw_funcs_t that feeds outline data into + * @draw. Pass @draw as the @draw_data argument when calling + * the draw functions. * * Return value: (transfer none): * The rasterizer draw functions * - * Since: 13.0.0 + * Since: 14.2.0 **/ hb_draw_funcs_t * -hb_raster_draw_get_funcs (void) +hb_raster_draw_get_funcs (const hb_raster_draw_t *draw HB_UNUSED) { return static_raster_draw_funcs.get_unconst (); } +/** + * hb_raster_draw_glyph_or_fail: + * @draw: a rasterizer + * @font: font to draw from + * @glyph: glyph ID to draw + * + * Convenience to draw one glyph. Equivalent to: + * + * |[ + * hb_font_draw_glyph_or_fail (font, glyph, + * hb_raster_draw_get_funcs (draw), draw); + * ]| + * + * Return value: `true` if the glyph was drawn, `false` if the font has + * no outlines for @glyph. + * + * Since: 14.2.0 + **/ +hb_bool_t +hb_raster_draw_glyph_or_fail (hb_raster_draw_t *draw, + hb_font_t *font, + hb_codepoint_t glyph) +{ + return hb_font_draw_glyph_or_fail (font, glyph, + hb_raster_draw_get_funcs (draw), draw); +} + /** * hb_raster_draw_glyph: * @draw: a rasterizer * @font: font to draw from * @glyph: glyph ID to draw - * @pen_x: glyph origin x in font coordinates (pre-transform) - * @pen_y: glyph origin y in font coordinates (pre-transform) * - * Convenience wrapper to draw one glyph at (@pen_x, @pen_y) using the - * rasterizer's current transform. The pen coordinates are applied before - * minification and are transformed by the current affine transform. + * Draws one glyph into @draw using the rasterizer's current + * transform. Equivalent to hb_raster_draw_glyph_or_fail() with the + * return value ignored. * - * Since: 13.0.0 + * Since: 14.2.0 **/ void hb_raster_draw_glyph (hb_raster_draw_t *draw, hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y) + hb_codepoint_t glyph) { - float xx = draw->transform.xx; - float yx = draw->transform.yx; - float xy = draw->transform.xy; - float yy = draw->transform.yy; - float dx = draw->transform.x0; - float dy = draw->transform.y0; - - hb_raster_draw_set_transform (draw, - xx, yx, xy, yy, - dx + xx * pen_x + xy * pen_y, - dy + yx * pen_x + yy * pen_y); - hb_font_draw_glyph (font, glyph, hb_raster_draw_get_funcs (), draw); - hb_raster_draw_set_transform (draw, xx, yx, xy, yy, dx, dy); + hb_raster_draw_glyph_or_fail (draw, font, glyph); } @@ -1033,9 +1063,14 @@ edge_sweep_row (int32_t *area, int32_t ey1 = hb_min (edge.yH, y_bot); if (ey0 >= ey1) return; - /* X at clipped endpoints (fixed-point) */ - int32_t x0 = edge.xL + (int32_t) ((int64_t) (ey0 - edge.yL) * edge.slope >> 16); - int32_t x1 = edge.xL + (int32_t) ((int64_t) (ey1 - edge.yL) * edge.slope >> 16); + /* X at clipped endpoints (fixed-point). Keep the interpolation in 64-bit + * so extreme y values do not overflow before the slope multiply. */ + int64_t x0_64 = (int64_t) edge.xL + + ((((int64_t) ey0 - (int64_t) edge.yL) * edge.slope) >> 16); + int64_t x1_64 = (int64_t) edge.xL + + ((((int64_t) ey1 - (int64_t) edge.yL) * edge.slope) >> 16); + int32_t x0 = (int32_t) hb_clamp (x0_64, (int64_t) INT32_MIN, (int64_t) INT32_MAX); + int32_t x1 = (int32_t) hb_clamp (x1_64, (int64_t) INT32_MIN, (int64_t) INT32_MAX); /* Fractional y within this pixel row [0, ONE_PIXEL] */ int32_t fy0 = ey0 - y_top; @@ -1054,8 +1089,8 @@ edge_sweep_row (int32_t *area, return; } - int32_t total_dx = x1 - x0; - int32_t total_dy = fy1 - fy0; + int64_t total_dx = (int64_t) x1 - (int64_t) x0; + int64_t total_dy = (int64_t) fy1 - (int64_t) fy0; /* fy increment per pixel column (constant since x_b advances by ONE_PIXEL). */ int32_t delta_fy = (int32_t) ((int64_t) HB_RASTER_ONE_PIXEL * total_dy / total_dx); @@ -1063,8 +1098,9 @@ edge_sweep_row (int32_t *area, if (total_dx > 0) { /* Left-to-right edge. */ - int32_t x_b = (cx0 + 1) << HB_RASTER_PIXEL_BITS; - int32_t fy_b = fy0 + (int32_t) ((int64_t) (x_b - x0) * total_dy / total_dx); + int32_t x_b = (int32_t) hb_clamp (((int64_t) cx0 + 1) * HB_RASTER_ONE_PIXEL, + (int64_t) INT32_MIN, (int64_t) INT32_MAX); + int32_t fy_b = fy0 + (int32_t) ((((int64_t) x_b - (int64_t) x0) * total_dy) / total_dx); cell_add (area, cover, width, cx0 - x_org, fx0, fy0, HB_RASTER_ONE_PIXEL, fy_b, wind, x_min, x_max); int32_t fy_prev = fy_b; @@ -1080,8 +1116,9 @@ edge_sweep_row (int32_t *area, else { /* Right-to-left edge. */ - int32_t x_b = cx0 << HB_RASTER_PIXEL_BITS; - int32_t fy_b = fy0 + (int32_t) ((int64_t) (x_b - x0) * total_dy / total_dx); + int32_t x_b = (int32_t) hb_clamp ((int64_t) cx0 * HB_RASTER_ONE_PIXEL, + (int64_t) INT32_MIN, (int64_t) INT32_MAX); + int32_t fy_b = fy0 + (int32_t) ((((int64_t) x_b - (int64_t) x0) * total_dy) / total_dx); cell_add (area, cover, width, cx0 - x_org, fx0, fy0, 0, fy_b, wind, x_min, x_max); int32_t fy_prev = fy_b; @@ -1271,24 +1308,23 @@ hb_raster_draw_render (hb_raster_draw_t *draw) ext.stride = (ext.width + 3u) & ~3u; /* ── 3. Allocate or reuse image ─────────────────────────────────── */ - hb_raster_image_t *image; + /* Reset one-shot state on every exit path. */ + HB_SCOPE_GUARD (hb_raster_draw_clear (draw)); + + hb_unique_ptr_t image; if (draw->recycled_image) { - image = draw->recycled_image; + image = hb_unique_ptr_t (draw->recycled_image); draw->recycled_image = nullptr; } else { - image = hb_raster_image_create_or_fail (); - if (unlikely (!image)) goto fail; + image = hb_unique_ptr_t (hb_raster_image_create_or_fail ()); + if (unlikely (!image)) return nullptr; } if (unlikely (!image->configure (HB_RASTER_FORMAT_A8, ext))) - { - hb_raster_image_destroy (image); - image = nullptr; - goto fail; - } + return nullptr; image->clear (); /* ── 4. Bucket edges by starting row and rasterize scanlines ──── */ @@ -1296,7 +1332,7 @@ hb_raster_draw_render (hb_raster_draw_t *draw) { if (unlikely (!draw->row_area.resize_dirty (ext.width) || !draw->row_cover.resize_dirty (ext.width))) - goto fail; + return nullptr; hb_memset (draw->row_area.arrayZ, 0, ext.width * sizeof (int32_t)); hb_memset (draw->row_cover.arrayZ, 0, ext.width * sizeof (int16_t)); @@ -1306,7 +1342,7 @@ hb_raster_draw_render (hb_raster_draw_t *draw) if (ext.height > old_buckets) { if (unlikely (!draw->edge_buckets.resize (ext.height))) - goto fail; + return nullptr; } for (unsigned i = 0; i < hb_min (ext.height, old_buckets); i++) draw->edge_buckets.arrayZ[i].clear (); @@ -1325,7 +1361,8 @@ hb_raster_draw_render (hb_raster_draw_t *draw) for (unsigned row = 0; row < ext.height; row++) { - int32_t y_top = (ext.y_origin + (int) row) << HB_RASTER_PIXEL_BITS; + int64_t y_top_64 = ((int64_t) ext.y_origin + (int64_t) row) * HB_RASTER_ONE_PIXEL; + int32_t y_top = (int32_t) hb_clamp (y_top_64, (int64_t) INT32_MIN, (int64_t) INT32_MAX); /* Add new edges from this row's bucket. */ draw->active_edges.extend (draw->edge_buckets.arrayZ[row]); @@ -1368,16 +1405,5 @@ hb_raster_draw_render (hb_raster_draw_t *draw) } } -done: - /* ── 6. Reset one-shot state ────────────────────────────────────── */ - draw->edges.clear (); - draw->has_extents = false; - draw->fixed_extents = {}; - - return image; - -fail: - hb_raster_image_destroy (image); - image = nullptr; - goto done; + return image.release (); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.cc index aaff8c79c2..baf825279c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.cc @@ -30,6 +30,120 @@ #include +#ifdef HAVE_PNG +#include +#endif + +#ifdef HAVE_PNG +struct hb_raster_png_read_blob_t +{ + const uint8_t *data = nullptr; + size_t size = 0; + size_t offset = 0; + uint8_t *rgba = nullptr; + png_bytep *rows = nullptr; +}; + +static void +hb_raster_png_error (png_structp png, + png_const_charp msg HB_UNUSED) +{ +#ifdef PNG_SETJMP_SUPPORTED + longjmp (png_jmpbuf (png), 1); +#endif +} + +static void +hb_raster_png_warning (png_structp png HB_UNUSED, + png_const_charp msg HB_UNUSED) +{} + +static void +hb_raster_png_read_blob (png_structp png, png_bytep out, png_size_t length) +{ + hb_raster_png_read_blob_t *r = (hb_raster_png_read_blob_t *) png_get_io_ptr (png); + + if (!r || !r->data || length > r->size - r->offset) + png_error (png, "read error"); + + hb_memcpy (out, r->data + r->offset, length); + r->offset += length; +} + +static void +hb_raster_png_read_blob_fini (hb_raster_png_read_blob_t *r) +{ + if (!r) + return; + + hb_free (r->rgba); + hb_free (r->rows); + hb_free (r); +} + +struct hb_raster_png_write_blob_t +{ + char *data = nullptr; + size_t length = 0; + size_t allocated = 0; + uint8_t *rgba = nullptr; + png_bytep *rows = nullptr; +}; + +static void +hb_raster_png_write_blob (png_structp png, png_bytep in, png_size_t length) +{ + hb_raster_png_write_blob_t *w = (hb_raster_png_write_blob_t *) png_get_io_ptr (png); + if (!w) + png_error (png, "write error"); + + size_t old_length = w->length; + if ((size_t) length > (size_t) -1 - old_length) + png_error (png, "write error"); + + size_t new_length = old_length + length; + if (new_length > w->allocated) + { + size_t new_allocated = w->allocated ? w->allocated : 4096; + while (new_allocated < new_length) + { + size_t next = new_allocated * 2; + if (next <= new_allocated) + { + new_allocated = new_length; + break; + } + new_allocated = next; + } + + char *data = (char *) hb_realloc (w->data, new_allocated); + if (!data) + png_error (png, "write error"); + w->data = data; + w->allocated = new_allocated; + } + + hb_memcpy (w->data + old_length, in, length); + w->length = new_length; +} + +static void +hb_raster_png_flush_blob (png_structp png HB_UNUSED) +{} + +static void +hb_raster_png_write_blob_fini (hb_raster_png_write_blob_t *w) +{ + if (!w) + return; + + hb_free (w->data); + hb_free (w->rgba); + hb_free (w->rows); + hb_free (w); +} +#endif + /* * Image compositing @@ -335,8 +449,6 @@ composite_pixel (uint32_t src, uint32_t dst, /* hb_raster_image_t */ -#define HB_RASTER_IMAGE_MAX_BUFFER_SIZE ((size_t) 1 << 30) - unsigned hb_raster_image_t::bytes_per_pixel (hb_raster_format_t format) { @@ -363,7 +475,7 @@ hb_raster_image_t::configure (hb_raster_format_t format, return false; size_t buf_size = (size_t) extents.stride * extents.height; - if (buf_size > HB_RASTER_IMAGE_MAX_BUFFER_SIZE) + if (buf_size > HB_RASTER_MAX_BUFFER_SIZE) return false; if (unlikely (!buffer.resize_dirty (buf_size))) return false; @@ -373,6 +485,303 @@ hb_raster_image_t::configure (hb_raster_format_t format, return true; } +bool +hb_raster_image_t::deserialize_from_png (hb_blob_t *blob) +{ +#ifndef HAVE_PNG + return false; +#else + if (!blob) + return false; + + unsigned blob_len = 0; + const uint8_t *blob_data = (const uint8_t *) hb_blob_get_data (blob, &blob_len); + if (!blob_data || !blob_len) + return false; + + png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, + hb_raster_png_error, + hb_raster_png_warning); + if (!png) + return false; + + png_infop info = png_create_info_struct (png); + if (!info) + { + png_destroy_read_struct (&png, nullptr, nullptr); + return false; + } + + hb_raster_png_read_blob_t *reader = (hb_raster_png_read_blob_t *) hb_calloc (1, sizeof (*reader)); + if (!reader) + { + png_destroy_read_struct (&png, &info, nullptr); + return false; + } + + reader->data = blob_data; + reader->size = (size_t) blob_len; + png_set_read_fn (png, reader, hb_raster_png_read_blob); + if (setjmp (png_jmpbuf (png))) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + png_read_info (png, info); + + png_uint_32 w = 0, h = 0; + int bit_depth = 0, color_type = 0; + int interlace_type = 0, compression_type = 0, filter_method = 0; + png_get_IHDR (png, info, &w, &h, &bit_depth, &color_type, + &interlace_type, &compression_type, &filter_method); + + if (!w || !h || w > (png_uint_32) INT_MAX || h > (png_uint_32) INT_MAX) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + bool has_trns = png_get_valid (png, info, PNG_INFO_tRNS); + + if (bit_depth == 16) + png_set_strip_16 (png); + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8 (png); + if (has_trns) + png_set_tRNS_to_alpha (png); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb (png); + if (!(color_type & PNG_COLOR_MASK_ALPHA) && !has_trns) + png_set_add_alpha (png, 0xff, PNG_FILLER_AFTER); + if (interlace_type != PNG_INTERLACE_NONE) + png_set_interlace_handling (png); + + png_read_update_info (png, info); + + if (png_get_bit_depth (png, info) != 8 || png_get_channels (png, info) != 4) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + png_size_t rowbytes = png_get_rowbytes (png, info); + if (rowbytes < (png_size_t) w * 4u) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + size_t rgba_size = (size_t) rowbytes * (size_t) h; + if (h && rgba_size / (size_t) h != (size_t) rowbytes) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + reader->rgba = (uint8_t *) hb_malloc (rgba_size); + if (!reader->rgba) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + size_t rows_size = (size_t) h * sizeof (png_bytep); + if (h && rows_size / (size_t) h != sizeof (png_bytep)) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + reader->rows = (png_bytep *) hb_malloc (rows_size); + if (!reader->rows) + { + png_destroy_read_struct (&png, &info, nullptr); + hb_raster_png_read_blob_fini (reader); + return false; + } + + for (unsigned y = 0; y < (unsigned) h; y++) + reader->rows[y] = (png_bytep) (reader->rgba + (size_t) y * (size_t) rowbytes); + + png_read_image (png, reader->rows); + png_read_end (png, nullptr); + png_destroy_read_struct (&png, &info, nullptr); + + hb_raster_image_t decoded; + hb_raster_extents_t decoded_extents = {0, 0, (unsigned) w, (unsigned) h, 0}; + if (!decoded.configure (HB_RASTER_FORMAT_BGRA32, decoded_extents)) + { + hb_raster_png_read_blob_fini (reader); + return false; + } + + for (unsigned y = 0; y < (unsigned) h; y++) + { + hb_packed_t *dst = (hb_packed_t *) (decoded.buffer.arrayZ + (size_t) ((unsigned) h - 1 - y) * decoded.extents.stride); + const uint8_t *src = reader->rgba + (size_t) y * (size_t) rowbytes; + for (unsigned x = 0; x < (unsigned) w; x++) + { + uint8_t r = src[4 * x + 0]; + uint8_t g = src[4 * x + 1]; + uint8_t b = src[4 * x + 2]; + uint8_t a = src[4 * x + 3]; + dst[x] = hb_packed_t ((uint32_t) hb_raster_div255 (b * a) + | ((uint32_t) hb_raster_div255 (g * a) << 8) + | ((uint32_t) hb_raster_div255 (r * a) << 16) + | ((uint32_t) a << 24)); + } + } + + hb_swap (buffer, decoded.buffer); + hb_swap (this->extents, decoded.extents); + hb_swap (format, decoded.format); + hb_raster_png_read_blob_fini (reader); + return true; +#endif +} + +hb_blob_t * +hb_raster_image_t::serialize_to_png_or_fail () const +{ +#ifndef HAVE_PNG + return nullptr; +#else + if (format != HB_RASTER_FORMAT_BGRA32 || !extents.width || !extents.height) + return nullptr; + + png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, + hb_raster_png_error, + hb_raster_png_warning); + if (!png) + return nullptr; + + png_infop info = png_create_info_struct (png); + if (!info) + { + png_destroy_write_struct (&png, nullptr); + return nullptr; + } + + hb_raster_png_write_blob_t *writer = (hb_raster_png_write_blob_t *) hb_calloc (1, sizeof (*writer)); + if (!writer) + { + png_destroy_write_struct (&png, &info); + return nullptr; + } + + png_set_write_fn (png, writer, hb_raster_png_write_blob, hb_raster_png_flush_blob); + if (setjmp (png_jmpbuf (png))) + { + png_destroy_write_struct (&png, &info); + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + png_set_IHDR (png, info, + extents.width, extents.height, + 8, PNG_COLOR_TYPE_RGBA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info (png, info); + + size_t rowbytes = (size_t) extents.width * 4u; + size_t rgba_size = rowbytes * (size_t) extents.height; + if (extents.height && rgba_size / (size_t) extents.height != rowbytes) + { + png_destroy_write_struct (&png, &info); + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + writer->rgba = (uint8_t *) hb_malloc (rgba_size); + if (!writer->rgba) + { + png_destroy_write_struct (&png, &info); + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + size_t rows_size = (size_t) extents.height * sizeof (png_bytep); + if (extents.height && rows_size / (size_t) extents.height != sizeof (png_bytep)) + { + png_destroy_write_struct (&png, &info); + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + writer->rows = (png_bytep *) hb_malloc (rows_size); + if (!writer->rows) + { + png_destroy_write_struct (&png, &info); + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + for (unsigned y = 0; y < extents.height; y++) + { + uint8_t *dst = writer->rgba + (size_t) y * rowbytes; + const uint8_t *src = buffer.arrayZ + (size_t) (extents.height - 1 - y) * extents.stride; + + for (unsigned x = 0; x < extents.width; x++) + { + uint32_t px; + hb_memcpy (&px, src + x * 4, 4); + uint8_t b = (uint8_t) (px & 0xFF); + uint8_t g = (uint8_t) ((px >> 8) & 0xFF); + uint8_t r = (uint8_t) ((px >> 16) & 0xFF); + uint8_t a = (uint8_t) (px >> 24); + + dst[4 * x + 3] = a; + if (a) + { + dst[4 * x + 0] = (uint8_t) hb_min (255u, ((unsigned) r * 255u + a / 2u) / a); + dst[4 * x + 1] = (uint8_t) hb_min (255u, ((unsigned) g * 255u + a / 2u) / a); + dst[4 * x + 2] = (uint8_t) hb_min (255u, ((unsigned) b * 255u + a / 2u) / a); + } + else + dst[4 * x + 0] = dst[4 * x + 1] = dst[4 * x + 2] = 0; + } + + writer->rows[y] = (png_bytep) dst; + } + + png_write_image (png, writer->rows); + png_write_end (png, info); + png_destroy_write_struct (&png, &info); + + if (writer->length > (size_t) (unsigned) -1) + { + hb_raster_png_write_blob_fini (writer); + return nullptr; + } + + unsigned length = (unsigned) writer->length; + char *data = writer->data; + writer->data = nullptr; + hb_raster_png_write_blob_fini (writer); + if (!data && length) + return nullptr; + + hb_blob_t *blob = hb_blob_create_or_fail (data, length, + HB_MEMORY_MODE_WRITABLE, + data, hb_free); + if (!blob) + hb_free (data); + return blob; +#endif +} + void hb_raster_image_t::clear () { @@ -396,10 +805,10 @@ hb_raster_image_t::composite_from (const hb_raster_image_t *src, for (unsigned y = 0; y < h; y++) { - uint32_t *dp = reinterpret_cast (buffer.arrayZ + y * stride); - const uint32_t *sp = reinterpret_cast (src->buffer.arrayZ + y * stride); + hb_packed_t *dp = (hb_packed_t *) (buffer.arrayZ + y * stride); + const hb_packed_t *sp = (const hb_packed_t *) (src->buffer.arrayZ + y * stride); for (unsigned x = 0; x < w; x++) - dp[x] = composite_pixel (sp[x], dp[x], mode); + dp[x] = hb_packed_t (composite_pixel ((uint32_t) sp[x], (uint32_t) dp[x], mode)); } } @@ -509,7 +918,7 @@ hb_raster_image_set_user_data (hb_raster_image_t *image, * Since: 13.0.0 **/ void * -hb_raster_image_get_user_data (hb_raster_image_t *image, +hb_raster_image_get_user_data (const hb_raster_image_t *image, hb_user_data_key_t *key) { return hb_object_get_user_data (image, key); @@ -566,7 +975,8 @@ hb_raster_image_clear (hb_raster_image_t *image) * * Fetches the raw pixel buffer of @image. The buffer layout is * described by the extents obtained from hb_raster_image_get_extents() - * and the format from hb_raster_image_get_format(). + * and the format from hb_raster_image_get_format(). Rows are stored + * bottom-to-top. * * Return value: (transfer none) (array): * The pixel buffer, or `NULL` @@ -574,7 +984,7 @@ hb_raster_image_clear (hb_raster_image_t *image) * Since: 13.0.0 **/ const uint8_t * -hb_raster_image_get_buffer (hb_raster_image_t *image) +hb_raster_image_get_buffer (const hb_raster_image_t *image) { return image->get_buffer (); } @@ -589,7 +999,7 @@ hb_raster_image_get_buffer (hb_raster_image_t *image) * Since: 13.0.0 **/ void -hb_raster_image_get_extents (hb_raster_image_t *image, +hb_raster_image_get_extents (const hb_raster_image_t *image, hb_raster_extents_t *extents) { if (extents) @@ -608,7 +1018,49 @@ hb_raster_image_get_extents (hb_raster_image_t *image, * Since: 13.0.0 **/ hb_raster_format_t -hb_raster_image_get_format (hb_raster_image_t *image) +hb_raster_image_get_format (const hb_raster_image_t *image) { return image->format; } + +/** + * hb_raster_image_deserialize_from_png_or_fail: + * @image: a raster image + * @png: PNG data + * + * Replaces @image contents by deserializing a PNG blob into a + * #HB_RASTER_FORMAT_BGRA32 raster image. + * + * On success, @image extents are reset to pixel extents with origin + * `(0, 0)`. Rows in the resulting image buffer are stored bottom-to-top. + * On failure, @image is left unchanged. + * + * Return value: `true` if deserialization succeeded, `false` otherwise + * + * Since: 13.1.0 + **/ +hb_bool_t +hb_raster_image_deserialize_from_png_or_fail (hb_raster_image_t *image, + hb_blob_t *png) +{ + return image->deserialize_from_png (png); +} + +/** + * hb_raster_image_serialize_to_png_or_fail: + * @image: a raster image + * + * Serializes @image to a PNG blob. + * + * Currently only #HB_RASTER_FORMAT_BGRA32 images are supported. + * + * Return value: (transfer full): + * A newly allocated PNG #hb_blob_t, or `NULL` on failure + * + * Since: 13.1.0 + **/ +hb_blob_t * +hb_raster_image_serialize_to_png_or_fail (const hb_raster_image_t *image) +{ + return image->serialize_to_png_or_fail (); +} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.hh index 89906dfedf..dcd13ffc92 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-image.hh @@ -28,7 +28,7 @@ #define HB_RASTER_IMAGE_HH #include "hb.hh" -#include "hb-raster-utils.hh" +#include "hb-raster.hh" #include "hb-raster.h" #include "hb-object.hh" #include "hb-vector.hh" @@ -43,12 +43,14 @@ struct hb_raster_image_t hb_raster_extents_t extents = {}; hb_raster_format_t format = HB_RASTER_FORMAT_A8; - static unsigned bytes_per_pixel (hb_raster_format_t format); - bool configure (hb_raster_format_t format, hb_raster_extents_t extents); - void clear (); - const uint8_t *get_buffer () const; - void composite_from (const hb_raster_image_t *src, - hb_paint_composite_mode_t mode); + HB_INTERNAL static unsigned bytes_per_pixel (hb_raster_format_t format); + HB_INTERNAL bool configure (hb_raster_format_t format, hb_raster_extents_t extents); + HB_INTERNAL bool deserialize_from_png (hb_blob_t *png); + HB_INTERNAL hb_blob_t *serialize_to_png_or_fail () const; + HB_INTERNAL void clear (); + HB_INTERNAL const uint8_t *get_buffer () const; + HB_INTERNAL void composite_from (const hb_raster_image_t *src, + hb_paint_composite_mode_t mode); }; /* Composite src image onto dst. */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.cc index 7914685c22..d5bcdd8b34 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.cc @@ -27,8 +27,8 @@ #include "hb.hh" #include "hb-raster-paint.hh" -#include "hb-raster-svg.hh" #include "hb-machinery.hh" +#include "hb-paint.hh" #include @@ -48,6 +48,51 @@ color_to_premul_pixel (hb_color_t color) return (uint32_t) b | ((uint32_t) g << 8) | ((uint32_t) r << 16) | ((uint32_t) a << 24); } +/* Bilinear sample from a premultiplied BGRA32 image. */ +static inline uint32_t +hb_raster_sample_bilinear_premul (const hb_packed_t *src, + unsigned width, + unsigned height, + float x, + float y) +{ + int x0 = (int) floorf (x); + int y0 = (int) floorf (y); + int x1 = x0 + 1; + int y1 = y0 + 1; + if (x1 >= (int) width) x1 = (int) width - 1; + if (y1 >= (int) height) y1 = (int) height - 1; + + float tx = x - x0; + float ty = y - y0; + float omtx = 1.f - tx; + float omty = 1.f - ty; + + uint32_t p00 = (uint32_t) src[(size_t) y0 * width + (size_t) x0]; + uint32_t p10 = (uint32_t) src[(size_t) y0 * width + (size_t) x1]; + uint32_t p01 = (uint32_t) src[(size_t) y1 * width + (size_t) x0]; + uint32_t p11 = (uint32_t) src[(size_t) y1 * width + (size_t) x1]; + + float w00 = omtx * omty; + float w10 = tx * omty; + float w01 = omtx * ty; + float w11 = tx * ty; + + float b = ((p00 >> 0) & 0xff) * w00 + ((p10 >> 0) & 0xff) * w10 + + ((p01 >> 0) & 0xff) * w01 + ((p11 >> 0) & 0xff) * w11; + float g = ((p00 >> 8) & 0xff) * w00 + ((p10 >> 8) & 0xff) * w10 + + ((p01 >> 8) & 0xff) * w01 + ((p11 >> 8) & 0xff) * w11; + float r = ((p00 >> 16) & 0xff) * w00 + ((p10 >> 16) & 0xff) * w10 + + ((p01 >> 16) & 0xff) * w01 + ((p11 >> 16) & 0xff) * w11; + float a = ((p00 >> 24) & 0xff) * w00 + ((p10 >> 24) & 0xff) * w10 + + ((p01 >> 24) & 0xff) * w01 + ((p11 >> 24) & 0xff) * w11; + + return (uint32_t) (b + 0.5f) + | ((uint32_t) (g + 0.5f) << 8) + | ((uint32_t) (r + 0.5f) << 16) + | ((uint32_t) (a + 0.5f) << 24); +} + /* * Paint callbacks @@ -65,15 +110,39 @@ ensure_initialized (hb_raster_paint_t *c) /* Root surface */ hb_raster_image_t *root = c->acquire_surface (); if (unlikely (!root)) return; - c->surface_stack.push (root); - /* Initial transform */ - c->transform_stack.push (c->base_transform); + if (hb_color_get_alpha (c->background)) + { + uint32_t bg = HB_COLOR (hb_color_get_blue (c->background), + hb_color_get_green (c->background), + hb_color_get_red (c->background), + hb_color_get_alpha (c->background)); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + uint32_t *pixels = (uint32_t *) hb_raster_image_get_buffer (root); +#pragma GCC diagnostic pop + hb_raster_extents_t ext; + hb_raster_image_get_extents (root, &ext); + unsigned count = ext.width * ext.height; + for (unsigned i = 0; i < count; i++) + pixels[i] = bg; + } + + if (unlikely (!c->surface_stack.push_or_fail (root))) + { + c->release_surface (root); + return; + } /* Initial clip: full coverage rectangle */ hb_raster_clip_t clip; clip.init_full (c->fixed_extents.width, c->fixed_extents.height); - c->clip_stack.push (std::move (clip)); + if (unlikely (!c->clip_stack.push_or_fail (std::move (clip)))) + { + c->transform_stack.pop (); + c->release_surface (c->surface_stack.pop ()); + return; + } } static void @@ -90,7 +159,7 @@ hb_raster_paint_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_transform_t<> t = c->current_transform (); t.multiply ({xx, yx, xy, yy, dx, dy}); - c->transform_stack.push (t); + (void) c->transform_stack.push (t); } static void @@ -99,7 +168,8 @@ hb_raster_paint_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, void *user_data HB_UNUSED) { hb_raster_paint_t *c = (hb_raster_paint_t *) paint_data; - c->transform_stack.pop (); + if (c->transform_stack.length) + c->transform_stack.pop (); } static hb_bool_t @@ -123,28 +193,20 @@ hb_raster_paint_push_empty_clip (hb_raster_paint_t *c, unsigned w, unsigned h) new_clip.rect_x0 = new_clip.rect_y0 = 0; new_clip.rect_x1 = new_clip.rect_y1 = 0; new_clip.min_x = new_clip.min_y = new_clip.max_x = new_clip.max_y = 0; - c->clip_stack.push (std::move (new_clip)); + (void) c->clip_stack.push (std::move (new_clip)); } +/* Render whatever edges have been accumulated into @rdr and + * push the result as a new clip on the stack, intersecting + * with the existing clip. Used by the emitter-based clip + * helpers (push_clip_glyph) and by push_clip_path_end once + * the caller has drawn the path into @rdr. */ static void -hb_raster_paint_push_clip_from_emitter (hb_raster_paint_t *c, - hb_raster_paint_clip_mask_emit_t emit, - void *emit_data) +hb_raster_paint_finalize_path_clip (hb_raster_paint_t *c, + hb_raster_draw_t *rdr, + hb_raster_image_t *surf, + unsigned w, unsigned h) { - ensure_initialized (c); - - hb_raster_image_t *surf = c->current_surface (); - if (unlikely (!surf)) return; - - unsigned w = surf->extents.width; - unsigned h = surf->extents.height; - - hb_raster_clip_t new_clip = c->acquire_clip (w, h); - - hb_raster_draw_t *rdr = c->clip_rdr; - hb_transform_t<> t = c->current_effective_transform (); - hb_raster_draw_set_transform (rdr, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0); - emit (rdr, emit_data); hb_raster_image_t *mask_img = hb_raster_draw_render (rdr); if (unlikely (!mask_img)) @@ -153,18 +215,29 @@ hb_raster_paint_push_clip_from_emitter (hb_raster_paint_t *c, return; } + hb_raster_clip_t new_clip = c->acquire_clip (w, h); + /* Allocate alpha buffer and intersect with previous clip */ - if (unlikely (!new_clip.alpha.resize (new_clip.stride * h))) + size_t clip_size = (size_t) new_clip.stride * h; + if (unlikely (clip_size > HB_RASTER_MAX_BUFFER_SIZE || + !new_clip.alpha.resize ((unsigned) clip_size))) { hb_raster_draw_recycle_image (rdr, mask_img); hb_raster_paint_push_empty_clip (c, w, h); return; } + hb_memset (new_clip.alpha.arrayZ, 0, (unsigned) clip_size); const uint8_t *mask_buf = hb_raster_image_get_buffer (mask_img); hb_raster_extents_t mask_ext; hb_raster_image_get_extents (mask_img, &mask_ext); const hb_raster_clip_t &old_clip = c->current_clip (); + if (unlikely (!old_clip.has_valid_alpha_mask ())) + { + hb_raster_draw_recycle_image (rdr, mask_img); + hb_raster_paint_push_empty_clip (c, w, h); + return; + } /* Convert mask extents from surface coordinates to clip-buffer coordinates. */ int mask_x0 = mask_ext.x_origin - surf->extents.x_origin; @@ -253,7 +326,29 @@ hb_raster_paint_push_clip_from_emitter (hb_raster_paint_t *c, } hb_raster_draw_recycle_image (rdr, mask_img); - c->clip_stack.push (std::move (new_clip)); + if (unlikely (!c->clip_stack.push_or_fail (std::move (new_clip)))) + hb_raster_paint_push_empty_clip (c, w, h); +} + +static void +hb_raster_paint_push_clip_from_emitter (hb_raster_paint_t *c, + hb_raster_paint_clip_mask_emit_t emit, + void *emit_data) +{ + ensure_initialized (c); + + hb_raster_image_t *surf = c->current_surface (); + if (unlikely (!surf)) return; + + unsigned w = surf->extents.width; + unsigned h = surf->extents.height; + + hb_raster_draw_t *rdr = c->clip_rdr; + hb_transform_t<> t = c->current_effective_transform (); + hb_raster_draw_set_transform (rdr, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0); + emit (rdr, emit_data); + + hb_raster_paint_finalize_path_clip (c, rdr, surf, w, h); } struct hb_raster_paint_glyph_clip_data_t @@ -267,7 +362,7 @@ hb_raster_paint_emit_clip_glyph_mask (hb_raster_draw_t *rdr, void *user_data) { hb_raster_paint_glyph_clip_data_t *data = (hb_raster_paint_glyph_clip_data_t *) user_data; /* Let draw-render choose tight glyph extents; we map by mask origin below. */ - hb_font_draw_glyph (data->font, data->glyph, hb_raster_draw_get_funcs (), rdr); + hb_font_draw_glyph (data->font, data->glyph, hb_raster_draw_get_funcs (rdr), rdr); } static void @@ -282,30 +377,6 @@ hb_raster_paint_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_paint_push_clip_from_emitter (c, hb_raster_paint_emit_clip_glyph_mask, &data); } -/* Push clip from arbitrary path emitter (used by SVG rasterizer). - * Identical to push_clip_glyph but calls user func instead of hb_font_draw_glyph. */ -struct hb_raster_paint_path_clip_data_t -{ - hb_raster_svg_path_func_t func; - void *user_data; -}; - -static void -hb_raster_paint_emit_clip_path_mask (hb_raster_draw_t *rdr, void *user_data) -{ - hb_raster_paint_path_clip_data_t *data = (hb_raster_paint_path_clip_data_t *) user_data; - data->func (hb_raster_draw_get_funcs (), rdr, data->user_data); -} - -void -hb_raster_paint_push_clip_path (hb_raster_paint_t *c, - hb_raster_svg_path_func_t func, - void *user_data) -{ - hb_raster_paint_path_clip_data_t data = {func, user_data}; - hb_raster_paint_push_clip_from_emitter (c, hb_raster_paint_emit_clip_path_mask, &data); -} - static void hb_raster_paint_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, void *paint_data, @@ -357,6 +428,11 @@ hb_raster_paint_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, py1 = hb_min (py1, (int) h); const hb_raster_clip_t &old_clip = c->current_clip (); + if (unlikely (!old_clip.has_valid_alpha_mask ())) + { + hb_raster_paint_push_empty_clip (c, w, h); + return; + } hb_raster_clip_t new_clip = c->acquire_clip (w, h); @@ -370,16 +446,55 @@ hb_raster_paint_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, new_clip.rect_y1 = hb_min (py1, old_clip.rect_y1); new_clip.update_bounds_from_rect (); } - else + else if (is_axis_aligned) { - /* General case: rasterize transformed quad as alpha mask */ + /* Fast path: intersect an axis-aligned rect with an existing alpha clip. */ new_clip.is_rect = false; - if (unlikely (!new_clip.alpha.resize (new_clip.stride * h))) + size_t clip_size = (size_t) new_clip.stride * h; + if (unlikely (clip_size > HB_RASTER_MAX_BUFFER_SIZE || + !new_clip.alpha.resize ((unsigned) clip_size))) { hb_raster_paint_push_empty_clip (c, w, h); return; } - hb_memset (new_clip.alpha.arrayZ, 0, new_clip.stride * h); + hb_memset (new_clip.alpha.arrayZ, 0, (unsigned) clip_size); + + int iy0_i = hb_max (py0, (int) old_clip.min_y); + int iy1_i = hb_min (py1, (int) old_clip.max_y); + int ix0_i = hb_max (px0, (int) old_clip.min_x); + int ix1_i = hb_min (px1, (int) old_clip.max_x); + + if (ix0_i < ix1_i && iy0_i < iy1_i) + { + unsigned iy0 = (unsigned) iy0_i; + unsigned iy1 = (unsigned) iy1_i; + unsigned ix0 = (unsigned) ix0_i; + unsigned ix1 = (unsigned) ix1_i; + + for (unsigned y = iy0; y < iy1; y++) + { + const uint8_t *old_row = old_clip.alpha.arrayZ + y * old_clip.stride; + uint8_t *new_row = new_clip.alpha.arrayZ + y * new_clip.stride; + hb_memcpy (new_row + ix0, old_row + ix0, ix1 - ix0); + } + new_clip.min_x = ix0; + new_clip.min_y = iy0; + new_clip.max_x = ix1; + new_clip.max_y = iy1; + } + } + else + { + /* General case: rasterize transformed quad as alpha mask */ + new_clip.is_rect = false; + size_t clip_size = (size_t) new_clip.stride * h; + if (unlikely (clip_size > HB_RASTER_MAX_BUFFER_SIZE || + !new_clip.alpha.resize ((unsigned) clip_size))) + { + hb_raster_paint_push_empty_clip (c, w, h); + return; + } + hb_memset (new_clip.alpha.arrayZ, 0, (unsigned) clip_size); /* Convert quad corners to pixel-relative coords */ float qx[4], qy[4]; @@ -393,82 +508,148 @@ hb_raster_paint_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, /* For each pixel in the bounding box, test if inside the quad * using cross-product edge tests (winding order). */ - unsigned iy0 = (unsigned) hb_max (py0, (int) old_clip.min_y); - unsigned iy1 = (unsigned) hb_min (py1, (int) old_clip.max_y); - unsigned ix0 = (unsigned) hb_max (px0, (int) old_clip.min_x); - unsigned ix1 = (unsigned) hb_min (px1, (int) old_clip.max_x); + int iy0_i = hb_max (py0, (int) old_clip.min_y); + int iy1_i = hb_min (py1, (int) old_clip.max_y); + int ix0_i = hb_max (px0, (int) old_clip.min_x); + int ix1_i = hb_min (px1, (int) old_clip.max_x); new_clip.min_x = w; new_clip.min_y = h; new_clip.max_x = 0; new_clip.max_y = 0; - /* Precompute edge normals for point-in-quad test. - * Edge i goes from corner i to corner (i+1)%4. - * Normal = (dy, -dx); inside test: dot(normal, p-corner) >= 0 */ - float enx[4], eny[4], ed[4]; - for (unsigned i = 0; i < 4; i++) + if (ix0_i < ix1_i && iy0_i < iy1_i) { - unsigned j = (i + 1) & 3; - float edx = qx[j] - qx[i], edy = qy[j] - qy[i]; - enx[i] = edy; /* normal x */ - eny[i] = -edx; /* normal y */ - ed[i] = enx[i] * qx[i] + eny[i] * qy[i]; /* distance threshold */ - } + unsigned iy0 = (unsigned) iy0_i; + unsigned iy1 = (unsigned) iy1_i; + unsigned ix0 = (unsigned) ix0_i; + unsigned ix1 = (unsigned) ix1_i; - if (old_clip.is_rect) - { - for (unsigned y = iy0; y < iy1; y++) - for (unsigned x = ix0; x < ix1; x++) - { - float px_f = x + 0.5f, py_f = y + 0.5f; - /* Test if pixel center is inside the quad */ - bool inside = true; - for (unsigned i = 0; i < 4; i++) - if (enx[i] * px_f + eny[i] * py_f < ed[i]) - { - inside = false; - break; - } - uint8_t a = inside ? 255 : 0; - new_clip.alpha[y * new_clip.stride + x] = a; - if (a) - { - new_clip.min_x = hb_min (new_clip.min_x, x); - new_clip.min_y = hb_min (new_clip.min_y, y); - new_clip.max_x = hb_max (new_clip.max_x, x + 1); - new_clip.max_y = hb_max (new_clip.max_y, y + 1); - } - } - } - else - { - for (unsigned y = iy0; y < iy1; y++) + /* Precompute edge normals for point-in-quad test. + * Edge i goes from corner i to corner (i+1)%4. + * Normal = (dy, -dx); inside test: dot(normal, p-corner) >= 0 */ + float enx[4], eny[4], ed[4]; + for (unsigned i = 0; i < 4; i++) + { + unsigned j = (i + 1) & 3; + float edx = qx[j] - qx[i], edy = qy[j] - qy[i]; + enx[i] = edy; /* normal x */ + eny[i] = -edx; /* normal y */ + ed[i] = enx[i] * qx[i] + eny[i] * qy[i]; /* distance threshold */ + } + float area2 = 0.f; + for (unsigned i = 0; i < 4; i++) + { + unsigned j = (i + 1) & 3; + area2 += qx[i] * qy[j] - qx[j] * qy[i]; + } + bool ccw = area2 >= 0.f; + + if (old_clip.is_rect) { - const uint8_t *old_row = old_clip.alpha.arrayZ + y * old_clip.stride; - for (unsigned x = ix0; x < ix1; x++) - { - float px_f = x + 0.5f, py_f = y + 0.5f; - /* Test if pixel center is inside the quad */ - bool inside = true; - for (unsigned i = 0; i < 4; i++) - if (enx[i] * px_f + eny[i] * py_f < ed[i]) - { - inside = false; - break; - } - uint8_t a = inside ? old_row[x] : 0; - new_clip.alpha[y * new_clip.stride + x] = a; - if (a) + for (unsigned y = iy0; y < iy1; y++) + for (unsigned x = ix0; x < ix1; x++) { - new_clip.min_x = hb_min (new_clip.min_x, x); - new_clip.min_y = hb_min (new_clip.min_y, y); - new_clip.max_x = hb_max (new_clip.max_x, x + 1); - new_clip.max_y = hb_max (new_clip.max_y, y + 1); + float px_f = x + 0.5f, py_f = y + 0.5f; + /* Test if pixel center is inside the quad */ + bool inside = true; + for (unsigned i = 0; i < 4; i++) + { + float d = enx[i] * px_f + eny[i] * py_f; + if (ccw ? d < ed[i] : d > ed[i]) + { + inside = false; + break; + } + } + uint8_t a = inside ? 255 : 0; + new_clip.alpha[y * new_clip.stride + x] = a; + if (a) + { + new_clip.min_x = hb_min (new_clip.min_x, x); + new_clip.min_y = hb_min (new_clip.min_y, y); + new_clip.max_x = hb_max (new_clip.max_x, x + 1); + new_clip.max_y = hb_max (new_clip.max_y, y + 1); + } + } + } + else + { + for (unsigned y = iy0; y < iy1; y++) + { + const uint8_t *old_row = old_clip.alpha.arrayZ + y * old_clip.stride; + for (unsigned x = ix0; x < ix1; x++) + { + float px_f = x + 0.5f, py_f = y + 0.5f; + /* Test if pixel center is inside the quad */ + bool inside = true; + for (unsigned i = 0; i < 4; i++) + { + float d = enx[i] * px_f + eny[i] * py_f; + if (ccw ? d < ed[i] : d > ed[i]) + { + inside = false; + break; + } + } + uint8_t a = inside ? old_row[x] : 0; + new_clip.alpha[y * new_clip.stride + x] = a; + if (a) + { + new_clip.min_x = hb_min (new_clip.min_x, x); + new_clip.min_y = hb_min (new_clip.min_y, y); + new_clip.max_x = hb_max (new_clip.max_x, x + 1); + new_clip.max_y = hb_max (new_clip.max_y, y + 1); + } } } } } } - c->clip_stack.push (std::move (new_clip)); + if (unlikely (!c->clip_stack.push_or_fail (std::move (new_clip)))) + hb_raster_paint_push_empty_clip (c, surf->extents.width, surf->extents.height); +} + +static hb_draw_funcs_t * +hb_raster_paint_push_clip_path_start (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void **draw_data, + void *user_data HB_UNUSED) +{ + hb_raster_paint_t *c = (hb_raster_paint_t *) paint_data; + + ensure_initialized (c); + + /* Prime clip_rdr with the current effective transform; the + * caller then drives hb_draw_*() into it, and _end renders + * the accumulated edges into a mask and intersects with the + * current clip. */ + if (unlikely (!c->surface_stack.length || !c->clip_rdr)) + { + *draw_data = nullptr; + return nullptr; + } + + hb_raster_draw_t *rdr = c->clip_rdr; + hb_transform_t<> t = c->current_effective_transform (); + hb_raster_draw_set_transform (rdr, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0); + + *draw_data = rdr; + return hb_raster_draw_get_funcs (rdr); +} + +static void +hb_raster_paint_push_clip_path_end (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_raster_paint_t *c = (hb_raster_paint_t *) paint_data; + + hb_raster_image_t *surf = c->current_surface (); + if (unlikely (!surf || !c->clip_rdr)) return; + + unsigned w = surf->extents.width; + unsigned h = surf->extents.height; + + hb_raster_paint_finalize_path_clip (c, c->clip_rdr, surf, w, h); } static void @@ -492,7 +673,8 @@ hb_raster_paint_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_image_t *new_surf = c->acquire_surface (); if (unlikely (!new_surf)) return; - c->surface_stack.push (new_surf); + if (unlikely (!c->surface_stack.push_or_fail (new_surf))) + c->release_surface (new_surf); } static void @@ -517,7 +699,7 @@ hb_raster_paint_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED, static void hb_raster_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, void *paint_data, - hb_bool_t is_foreground, + hb_bool_t is_foreground HB_UNUSED, hb_color_t color, void *user_data HB_UNUSED) { @@ -528,16 +710,6 @@ hb_raster_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_image_t *surf = c->current_surface (); if (unlikely (!surf)) return; - if (is_foreground) - { - /* Use foreground color, modulating alpha */ - color = HB_COLOR (hb_color_get_blue (c->foreground), - hb_color_get_green (c->foreground), - hb_color_get_red (c->foreground), - hb_raster_div255 (hb_color_get_alpha (c->foreground) * - hb_color_get_alpha (color))); - } - uint32_t premul = color_to_premul_pixel (color); uint8_t premul_a = (uint8_t) (premul >> 24); const hb_raster_clip_t &clip = c->current_clip (); @@ -550,7 +722,7 @@ hb_raster_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned y = clip.min_y; y < clip.max_y; y++) { - uint32_t *__restrict row = reinterpret_cast (surf->buffer.arrayZ + y * stride); + hb_packed_t *__restrict row = (hb_packed_t *) (surf->buffer.arrayZ + y * stride); const uint8_t *__restrict clip_row = clip.alpha.arrayZ + y * clip.stride; for (unsigned x = clip.min_x; x < clip.max_x; x++) { @@ -559,14 +731,14 @@ hb_raster_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, if (clip_alpha == 255) { if (premul_a == 255) - row[x] = premul; + row[x] = hb_packed_t (premul); else - row[x] = hb_raster_src_over (premul, row[x]); + row[x] = hb_packed_t (hb_raster_src_over (premul, (uint32_t) row[x])); } else { uint32_t src = hb_raster_alpha_mul (premul, clip_alpha); - row[x] = hb_raster_src_over (src, row[x]); + row[x] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[x])); } } } @@ -575,9 +747,9 @@ hb_raster_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned y = clip.min_y; y < clip.max_y; y++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + y * stride); + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + y * stride); for (unsigned x = clip.min_x; x < clip.max_x; x++) - row[x] = hb_raster_src_over (premul, row[x]); + row[x] = hb_packed_t (hb_raster_src_over (premul, (uint32_t) row[x])); } } } @@ -597,23 +769,50 @@ hb_raster_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, ensure_initialized (c); - /* Handle SVG format */ - if (format == HB_PAINT_IMAGE_FORMAT_SVG) - return hb_raster_svg_render (c, blob, c->svg_glyph, c->svg_font, - c->svg_palette, c->foreground); + unsigned src_width = width; + unsigned src_height = height; + const hb_packed_t *src_data = nullptr; + hb_raster_image_t decoded_png; - /* Only handle raw BGRA32 otherwise */ - if (format != HB_TAG ('B','G','R','A')) + if (format == HB_PAINT_IMAGE_FORMAT_BGRA) + { + if (src_width == 0 || src_height == 0) + return false; + if (src_width > (unsigned) INT_MAX || src_height > (unsigned) INT_MAX) + return false; + + unsigned data_len; + const uint8_t *data = (const uint8_t *) hb_blob_get_data (blob, &data_len); + size_t pixel_count = (size_t) src_width * (size_t) src_height; + if (src_width && pixel_count / src_width != src_height) + return false; + if (pixel_count > (size_t) -1 / 4u) + return false; + size_t required_size = pixel_count * 4u; + if (!data || (size_t) data_len < required_size) + return false; + + src_data = (const hb_packed_t *) data; + } + else if (format == HB_PAINT_IMAGE_FORMAT_PNG) + { +#ifdef HAVE_PNG + if (!decoded_png.deserialize_from_png (blob)) + return false; + src_width = decoded_png.extents.width; + src_height = decoded_png.extents.height; + src_data = (const hb_packed_t *) decoded_png.buffer.arrayZ; +#else + return false; +#endif + } + else return false; hb_raster_image_t *surf = c->current_surface (); if (unlikely (!surf)) return false; if (!extents) return false; - unsigned data_len; - const uint8_t *data = (const uint8_t *) hb_blob_get_data (blob, &data_len); - if (!data || data_len < width * height * 4) return false; - const hb_raster_clip_t &clip = c->current_clip (); hb_transform_t<> t = c->current_effective_transform (); @@ -634,32 +833,36 @@ hb_raster_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Image source rectangle in glyph space */ float img_x = extents->x_bearing; - float img_y = extents->y_bearing + extents->height; /* bottom-left in glyph space */ - float img_sx = (float) extents->width / width; - float img_sy = (float) -extents->height / height; /* flip Y */ + float img_y = extents->y_bearing; + float img_sx = (float) extents->width / src_width; + float img_sy = (float) extents->height / src_height; + if (fabsf (img_sx) < 1e-10f || fabsf (img_sy) < 1e-10f) + return false; if (clip.is_rect) { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * surf_stride); - float gx = inv_xx * (clip.min_x + ox) + inv_xy * (py + oy) + inv_x0; - float gy = inv_yx * (clip.min_x + ox) + inv_yy * (py + oy) + inv_y0; + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * surf_stride); + float gx = inv_xx * (float) ((int) clip.min_x + ox) + inv_xy * (float) ((int) py + oy) + inv_x0; + float gy = inv_yx * (float) ((int) clip.min_x + ox) + inv_yy * (float) ((int) py + oy) + inv_y0; for (unsigned px = clip.min_x; px < clip.max_x; px++) { - /* Map glyph space to image texel */ - int ix = (int) floorf ((gx - img_x) / img_sx); - int iy = (int) floorf ((gy - img_y) / img_sy); + /* Map glyph space to image texel; bilinear reconstruction. */ + float ix = (gx - img_x) / img_sx; + float iy = (float) (src_height - 1) - (gy - img_y) / img_sy; - if (ix < 0 || ix >= (int) width || iy < 0 || iy >= (int) height) + if (ix < 0.f || iy < 0.f || + ix > (float) (src_width - 1) || iy > (float) (src_height - 1)) { gx += inv_xx; gy += inv_yx; continue; } - uint32_t src_px = reinterpret_cast (data)[iy * width + ix]; - row[px] = hb_raster_src_over (src_px, row[px]); + uint32_t src_px = hb_raster_sample_bilinear_premul (src_data, src_width, src_height, + ix, iy); + row[px] = hb_packed_t (hb_raster_src_over (src_px, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -669,10 +872,10 @@ hb_raster_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * surf_stride); + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * surf_stride); const uint8_t *clip_row = clip.alpha.arrayZ + py * clip.stride; - float gx = inv_xx * (clip.min_x + ox) + inv_xy * (py + oy) + inv_x0; - float gy = inv_yx * (clip.min_x + ox) + inv_yy * (py + oy) + inv_y0; + float gx = inv_xx * (float) ((int) clip.min_x + ox) + inv_xy * (float) ((int) py + oy) + inv_x0; + float gy = inv_yx * (float) ((int) clip.min_x + ox) + inv_yy * (float) ((int) py + oy) + inv_y0; for (unsigned px = clip.min_x; px < clip.max_x; px++) { uint8_t clip_alpha = clip_row[px]; @@ -683,20 +886,22 @@ hb_raster_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, continue; } - /* Map glyph space to image texel */ - int ix = (int) floorf ((gx - img_x) / img_sx); - int iy = (int) floorf ((gy - img_y) / img_sy); + /* Map glyph space to image texel; bilinear reconstruction. */ + float ix = (gx - img_x) / img_sx; + float iy = (float) (src_height - 1) - (gy - img_y) / img_sy; - if (ix < 0 || ix >= (int) width || iy < 0 || iy >= (int) height) + if (ix < 0.f || iy < 0.f || + ix > (float) (src_width - 1) || iy > (float) (src_height - 1)) { gx += inv_xx; gy += inv_yx; continue; } - uint32_t src_px = reinterpret_cast (data)[iy * width + ix]; + uint32_t src_px = hb_raster_sample_bilinear_premul (src_data, src_width, src_height, + ix, iy); src_px = hb_raster_alpha_mul (src_px, clip_alpha); - row[px] = hb_raster_src_over (src_px, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src_px, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -711,65 +916,14 @@ hb_raster_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, * Gradient helpers */ -#define PREALLOCATED_COLOR_STOPS 16 #define GRADIENT_LUT_SIZE 256 #define GRADIENT_LUT_MIN_PIXELS (64u * 64u) -static int -cmp_color_stop (const void *p1, const void *p2) +static HB_ALWAYS_INLINE float +reflect_gradient_t (float t) { - const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1; - const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2; - if (c1->offset < c2->offset) return -1; - if (c1->offset > c2->offset) return 1; - return 0; -} - -static bool -get_color_stops (hb_raster_paint_t *c, - hb_color_line_t *color_line, - unsigned *count, - hb_color_stop_t **stops) -{ - unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); - if (len > *count) - { - if (unlikely (!c->scratch_color_stops.resize (len))) - return false; - *stops = c->scratch_color_stops.arrayZ; - } - hb_color_line_get_color_stops (color_line, 0, &len, *stops); - for (unsigned i = 0; i < len; i++) - if ((*stops)[i].is_foreground) - (*stops)[i].color = HB_COLOR (hb_color_get_blue (c->foreground), - hb_color_get_green (c->foreground), - hb_color_get_red (c->foreground), - hb_raster_div255 (hb_color_get_alpha (c->foreground) * - hb_color_get_alpha ((*stops)[i].color))); - - *count = len; - return true; -} - -static void -normalize_color_line (hb_color_stop_t *stops, - unsigned len, - float *omin, float *omax) -{ - hb_qsort (stops, len, sizeof (hb_color_stop_t), cmp_color_stop); - - float mn = stops[0].offset, mx = stops[0].offset; - for (unsigned i = 1; i < len; i++) - { - mn = hb_min (mn, stops[i].offset); - mx = hb_max (mx, stops[i].offset); - } - if (mn != mx) - for (unsigned i = 0; i < len; i++) - stops[i].offset = (stops[i].offset - mn) / (mx - mn); - - *omin = mn; - *omax = mx; + t = fmodf (fabsf (t), 2.f); + return t > 1.f ? 2.f - t : t; } /* Evaluate color at normalized position t, interpolating in premultiplied space. */ @@ -777,6 +931,13 @@ static uint32_t evaluate_color_line (const hb_color_stop_t *stops, unsigned len, float t, hb_paint_extend_t extend) { + if (unlikely (!len)) + return 0; + if (unlikely (len == 1)) + return color_to_premul_pixel (stops[0].color); + if (unlikely (!std::isfinite (t))) + t = 0.f; + /* Apply extend mode */ if (extend == HB_PAINT_EXTEND_PAD) { @@ -788,10 +949,7 @@ evaluate_color_line (const hb_color_stop_t *stops, unsigned len, float t, } else /* REFLECT */ { - if (t < 0) t = -t; - int period = (int) floorf (t); - float frac = t - (float) period; - t = (period & 1) ? 1.f - frac : frac; + t = reflect_gradient_t (t); } /* Find bounding stops */ @@ -838,6 +996,9 @@ evaluate_color_line (const hb_color_stop_t *stops, unsigned len, float t, static HB_ALWAYS_INLINE float normalize_gradient_t (float t, hb_paint_extend_t extend) { + if (unlikely (!std::isfinite (t))) + return 0.f; + if (extend == HB_PAINT_EXTEND_PAD) return hb_clamp (t, 0.f, 1.f); if (extend == HB_PAINT_EXTEND_REPEAT) @@ -847,10 +1008,7 @@ normalize_gradient_t (float t, hb_paint_extend_t extend) } /* REFLECT */ - if (t < 0.f) t = -t; - int period = (int) floorf (t); - float frac = t - (float) period; - return (period & 1) ? 1.f - frac : frac; + return reflect_gradient_t (t); } static void @@ -871,34 +1029,14 @@ lookup_gradient_lut (const uint32_t *lut, hb_paint_extend_t extend) { float u = normalize_gradient_t (t, extend); + if (unlikely (!std::isfinite (u))) + u = 0.f; + else + u = hb_clamp (u, 0.f, 1.f); unsigned idx = (unsigned) (u * (GRADIENT_LUT_SIZE - 1) + 0.5f); return lut[idx]; } -static void -reduce_anchors (float x0, float y0, - float x1, float y1, - float x2, float y2, - float *xx0, float *yy0, - float *xx1, float *yy1) -{ - float q2x = x2 - x0, q2y = y2 - y0; - float q1x = x1 - x0, q1y = y1 - y0; - float s = q2x * q2x + q2y * q2y; - if (s < 0.000001f) - { - *xx0 = x0; *yy0 = y0; - *xx1 = x1; *yy1 = y1; - return; - } - float k = (q2x * q1x + q2y * q1y) / s; - *xx0 = x0; - *yy0 = y0; - *xx1 = x1 - k * q2x; - *yy1 = y1 - k * q2y; -} - - /* * Gradient paint callbacks */ @@ -919,14 +1057,12 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_image_t *surf = c->current_surface (); if (unlikely (!surf)) return; - unsigned len = PREALLOCATED_COLOR_STOPS; - hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; - hb_color_stop_t *stops = stops_; - - if (unlikely (!get_color_stops (c, color_line, &len, &stops))) + if (unlikely (!c->fetch_color_stops (color_line))) return; + hb_color_stop_t *stops = c->scratch_color_stops.arrayZ; + unsigned len = c->scratch_color_stops.length; float mn, mx; - normalize_color_line (stops, len, &mn, &mx); + hb_paint_normalize_color_line (stops, len, &mn, &mx); hb_paint_extend_t extend = hb_color_line_get_extend (color_line); const hb_raster_clip_t &clip = c->current_clip (); @@ -939,7 +1075,8 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Reduce 3-point anchor to 2-point gradient axis */ float lx0, ly0, lx1, ly1; - reduce_anchors (x0, y0, x1, y1, x2, y2, &lx0, &ly0, &lx1, &ly1); + hb_paint_reduce_linear_anchors (x0, y0, x1, y1, x2, y2, + &lx0, &ly0, &lx1, &ly1); /* Apply normalization to endpoints */ float gx0 = lx0 + mn * (lx1 - lx0); @@ -950,7 +1087,7 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Inverse transform: pixel → glyph space */ hb_transform_t<> t = c->current_effective_transform (); float det = t.xx * t.yy - t.xy * t.yx; - if (fabsf (det) < 1e-10f) goto done; + if (fabsf (det) < 1e-10f) return; { float inv_det = 1.f / det; @@ -964,7 +1101,7 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Gradient direction vector and denominator for projection */ float dx = gx1 - gx0, dy = gy1 - gy0; float denom = dx * dx + dy * dy; - if (denom < 1e-10f) goto done; + if (denom < 1e-10f) return; float inv_denom = 1.f / denom; unsigned stride = surf->extents.stride; @@ -975,16 +1112,16 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) { float proj_t = ((gx - gx0) * dx + (gy - gy0) * dy) * inv_denom; uint32_t src = lookup_gradient_lut (lut, proj_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -995,7 +1132,7 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { float proj_t = ((gx - gx0) * dx + (gy - gy0) * dy) * inv_denom; uint32_t src = evaluate_color_line (stops, len, proj_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1006,10 +1143,10 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); const uint8_t *clip_row = clip.alpha.arrayZ + py * clip.stride; - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) @@ -1024,7 +1161,7 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, float proj_t = ((gx - gx0) * dx + (gy - gy0) * dy) * inv_denom; uint32_t src = lookup_gradient_lut (lut, proj_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1043,7 +1180,7 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, float proj_t = ((gx - gx0) * dx + (gy - gy0) * dy) * inv_denom; uint32_t src = evaluate_color_line (stops, len, proj_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1052,8 +1189,6 @@ hb_raster_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } } -done: - (void) stops_; } static void @@ -1071,14 +1206,12 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_image_t *surf = c->current_surface (); if (unlikely (!surf)) return; - unsigned len = PREALLOCATED_COLOR_STOPS; - hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; - hb_color_stop_t *stops = stops_; - - if (unlikely (!get_color_stops (c, color_line, &len, &stops))) + if (unlikely (!c->fetch_color_stops (color_line))) return; + hb_color_stop_t *stops = c->scratch_color_stops.arrayZ; + unsigned len = c->scratch_color_stops.length; float mn, mx; - normalize_color_line (stops, len, &mn, &mx); + hb_paint_normalize_color_line (stops, len, &mn, &mx); hb_paint_extend_t extend = hb_color_line_get_extend (color_line); const hb_raster_clip_t &clip = c->current_clip (); @@ -1100,7 +1233,7 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Inverse transform */ hb_transform_t<> t = c->current_effective_transform (); float det = t.xx * t.yy - t.xy * t.yx; - if (fabsf (det) < 1e-10f) goto done; + if (fabsf (det) < 1e-10f) return; { float inv_det = 1.f / det; @@ -1132,9 +1265,9 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) @@ -1147,7 +1280,12 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (fabsf (A) > 1e-10f) { float disc = B * B - 4.f * A * C; - if (disc < 0.f) continue; + if (disc < 0.f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } float sq = sqrtf (disc); /* Pick the larger root (t closer to 1 = outer circle) */ float t1 = (-B + sq) / (2.f * A); @@ -1161,12 +1299,17 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, else { /* Linear case: Bt + C = 0 */ - if (fabsf (B) < 1e-10f) continue; + if (fabsf (B) < 1e-10f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } grad_t = -C / B; } uint32_t src = lookup_gradient_lut (lut, grad_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1183,7 +1326,12 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (fabsf (A) > 1e-10f) { float disc = B * B - 4.f * A * C; - if (disc < 0.f) continue; + if (disc < 0.f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } float sq = sqrtf (disc); float t1 = (-B + sq) / (2.f * A); float t2 = (-B - sq) / (2.f * A); @@ -1191,12 +1339,17 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } else { - if (fabsf (B) < 1e-10f) continue; + if (fabsf (B) < 1e-10f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } grad_t = -C / B; } uint32_t src = evaluate_color_line (stops, len, grad_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1207,10 +1360,10 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); const uint8_t *clip_row = clip.alpha.arrayZ + py * clip.stride; - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) @@ -1230,7 +1383,12 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (fabsf (A) > 1e-10f) { float disc = B * B - 4.f * A * C; - if (disc < 0.f) continue; + if (disc < 0.f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } float sq = sqrtf (disc); float t1 = (-B + sq) / (2.f * A); float t2 = (-B - sq) / (2.f * A); @@ -1238,13 +1396,18 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } else { - if (fabsf (B) < 1e-10f) continue; + if (fabsf (B) < 1e-10f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } grad_t = -C / B; } uint32_t src = lookup_gradient_lut (lut, grad_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1268,7 +1431,12 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (fabsf (A) > 1e-10f) { float disc = B * B - 4.f * A * C; - if (disc < 0.f) continue; + if (disc < 0.f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } float sq = sqrtf (disc); float t1 = (-B + sq) / (2.f * A); float t2 = (-B - sq) / (2.f * A); @@ -1276,13 +1444,18 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } else { - if (fabsf (B) < 1e-10f) continue; + if (fabsf (B) < 1e-10f) + { + gx += inv_xx; + gy += inv_yx; + continue; + } grad_t = -C / B; } uint32_t src = evaluate_color_line (stops, len, grad_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1291,8 +1464,6 @@ hb_raster_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } } -done: - (void) stops_; } static void @@ -1311,14 +1482,12 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, hb_raster_image_t *surf = c->current_surface (); if (unlikely (!surf)) return; - unsigned len = PREALLOCATED_COLOR_STOPS; - hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; - hb_color_stop_t *stops = stops_; - - if (unlikely (!get_color_stops (c, color_line, &len, &stops))) + if (unlikely (!c->fetch_color_stops (color_line))) return; + hb_color_stop_t *stops = c->scratch_color_stops.arrayZ; + unsigned len = c->scratch_color_stops.length; float mn, mx; - normalize_color_line (stops, len, &mn, &mx); + hb_paint_normalize_color_line (stops, len, &mn, &mx); hb_paint_extend_t extend = hb_color_line_get_extend (color_line); const hb_raster_clip_t &clip = c->current_clip (); @@ -1337,7 +1506,7 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, /* Inverse transform */ hb_transform_t<> t = c->current_effective_transform (); float det = t.xx * t.yy - t.xy * t.yx; - if (fabsf (det) < 1e-10f || fabsf (angle_range) < 1e-10f) goto done; + if (fabsf (det) < 1e-10f || fabsf (angle_range) < 1e-10f) return; { float inv_det = 1.f / det; @@ -1358,9 +1527,9 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) @@ -1369,7 +1538,7 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (angle < 0) angle += (float) HB_2_PI; float grad_t = (angle - a0) * inv_angle_range; uint32_t src = lookup_gradient_lut (lut, grad_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1382,7 +1551,7 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, if (angle < 0) angle += (float) HB_2_PI; float grad_t = (angle - a0) * inv_angle_range; uint32_t src = evaluate_color_line (stops, len, grad_t, extend); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1393,10 +1562,10 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, { for (unsigned py = clip.min_y; py < clip.max_y; py++) { - uint32_t *row = reinterpret_cast (surf->buffer.arrayZ + py * stride); + hb_packed_t *row = (hb_packed_t *) (surf->buffer.arrayZ + py * stride); const uint8_t *clip_row = clip.alpha.arrayZ + py * clip.stride; - float gx = inv_xx * (clip.min_x + ox + 0.5f) + inv_xy * (py + oy + 0.5f) + inv_x0; - float gy = inv_yx * (clip.min_x + ox + 0.5f) + inv_yy * (py + oy + 0.5f) + inv_y0; + float gx = inv_xx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_xy * ((float) ((int) py + oy) + 0.5f) + inv_x0; + float gy = inv_yx * ((float) ((int) clip.min_x + ox) + 0.5f) + inv_yy * ((float) ((int) py + oy) + 0.5f) + inv_y0; if (use_lut) { for (unsigned px = clip.min_x; px < clip.max_x; px++) @@ -1413,7 +1582,7 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, float grad_t = (angle - a0) * inv_angle_range; uint32_t src = lookup_gradient_lut (lut, grad_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1434,7 +1603,7 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, float grad_t = (angle - a0) * inv_angle_range; uint32_t src = evaluate_color_line (stops, len, grad_t, extend); src = hb_raster_alpha_mul (src, clip_alpha); - row[px] = hb_raster_src_over (src, row[px]); + row[px] = hb_packed_t (hb_raster_src_over (src, (uint32_t) row[px])); gx += inv_xx; gy += inv_yx; } @@ -1443,8 +1612,6 @@ hb_raster_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, } } -done: - (void) stops_; } static hb_bool_t @@ -1481,6 +1648,8 @@ static struct hb_raster_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t hb_paint_funcs_set_color_glyph_func (funcs, hb_raster_paint_color_glyph, nullptr, nullptr); hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_raster_paint_push_clip_glyph, nullptr, nullptr); hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_raster_paint_push_clip_rectangle, nullptr, nullptr); + hb_paint_funcs_set_push_clip_path_start_func (funcs, hb_raster_paint_push_clip_path_start, nullptr, nullptr); + hb_paint_funcs_set_push_clip_path_end_func (funcs, hb_raster_paint_push_clip_path_end, nullptr, nullptr); hb_paint_funcs_set_pop_clip_func (funcs, hb_raster_paint_pop_clip, nullptr, nullptr); hb_paint_funcs_set_push_group_func (funcs, hb_raster_paint_push_group, nullptr, nullptr); hb_paint_funcs_set_pop_group_func (funcs, hb_raster_paint_pop_group, nullptr, nullptr); @@ -1566,13 +1735,16 @@ hb_raster_paint_reference (hb_raster_paint_t *paint) void hb_raster_paint_destroy (hb_raster_paint_t *paint) { - if (!hb_object_destroy (paint)) return; + if (!hb_object_should_destroy (paint)) + return; + hb_map_destroy (paint->custom_palette); hb_raster_draw_destroy (paint->clip_rdr); for (auto *s : paint->surface_stack) hb_raster_image_destroy (s); for (auto *s : paint->surface_cache) hb_raster_image_destroy (s); + hb_object_actually_destroy (paint); hb_free (paint); } @@ -1614,7 +1786,7 @@ hb_raster_paint_set_user_data (hb_raster_paint_t *paint, * Since: 13.0.0 **/ void * -hb_raster_paint_get_user_data (hb_raster_paint_t *paint, +hb_raster_paint_get_user_data (const hb_raster_paint_t *paint, hb_user_data_key_t *key) { return hb_object_get_user_data (paint, key); @@ -1659,7 +1831,7 @@ hb_raster_paint_set_transform (hb_raster_paint_t *paint, * Since: 13.0.0 **/ void -hb_raster_paint_get_transform (hb_raster_paint_t *paint, +hb_raster_paint_get_transform (const hb_raster_paint_t *paint, float *xx, float *yx, float *xy, float *yy, float *dx, float *dy) @@ -1703,7 +1875,7 @@ hb_raster_paint_set_scale_factor (hb_raster_paint_t *paint, * Since: 13.0.0 **/ void -hb_raster_paint_get_scale_factor (hb_raster_paint_t *paint, +hb_raster_paint_get_scale_factor (const hb_raster_paint_t *paint, float *x_scale_factor, float *y_scale_factor) { @@ -1720,11 +1892,11 @@ hb_raster_paint_get_scale_factor (hb_raster_paint_t *paint, * * Call this before hb_font_paint_glyph() for each render. * A common pattern is: - * ``` + * |[ * hb_glyph_extents_t gext; * if (hb_font_get_glyph_extents (font, gid, &gext)) * hb_raster_paint_set_glyph_extents (paint, &gext); - * ``` + * ]| * * Since: 13.0.0 **/ @@ -1750,7 +1922,7 @@ hb_raster_paint_set_extents (hb_raster_paint_t *paint, * Since: 13.0.0 **/ hb_bool_t -hb_raster_paint_get_extents (hb_raster_paint_t *paint, +hb_raster_paint_get_extents (const hb_raster_paint_t *paint, hb_raster_extents_t *extents) { if (!paint->has_extents) @@ -1853,6 +2025,92 @@ hb_raster_paint_set_foreground (hb_raster_paint_t *paint, paint->foreground = foreground; } +/** + * hb_raster_paint_get_foreground: + * @paint: a paint context + * + * Returns the foreground color previously set on @paint, or the + * default opaque black if none was set. + * + * Return value: the foreground color. + * + * Since: 14.2.0 + **/ +hb_color_t +hb_raster_paint_get_foreground (const hb_raster_paint_t *paint) +{ + return paint->foreground; +} + +/** + * hb_raster_paint_set_background: + * @paint: a paint context + * @background: the background color + * + * Sets the background color for @paint. If set to a non-transparent + * value, the rendered image is pre-filled with this color before + * glyph content is composited on top. Default is transparent. + * + * Since: 14.2.0 + **/ +void +hb_raster_paint_set_background (hb_raster_paint_t *paint, + hb_color_t background) +{ + paint->background = background; +} + +/** + * hb_raster_paint_get_background: + * @paint: a paint context + * + * Returns the background color previously set on @paint, or + * transparent if none was set. + * + * Return value: the background color. + * + * Since: 14.2.0 + **/ +hb_color_t +hb_raster_paint_get_background (const hb_raster_paint_t *paint) +{ + return paint->background; +} + +/** + * hb_raster_paint_set_palette: + * @paint: a paint context + * @palette: palette index + * + * Selects which font palette is used when paint callbacks look up + * indexed colors. Default is palette 0. + * + * Since: 14.2.0 + **/ +void +hb_raster_paint_set_palette (hb_raster_paint_t *paint, + unsigned palette) +{ + paint->palette = palette; +} + +/** + * hb_raster_paint_get_palette: + * @paint: a paint context + * + * Returns the palette index previously set on @paint, or 0 if none + * was set. + * + * Return value: the palette index. + * + * Since: 14.2.0 + **/ +unsigned +hb_raster_paint_get_palette (const hb_raster_paint_t *paint) +{ + return paint->palette; +} + /** * hb_raster_paint_clear_custom_palette_colors: * @paint: a paint context. @@ -1905,81 +2163,101 @@ hb_raster_paint_set_custom_palette_color (hb_raster_paint_t *paint, /** * hb_raster_paint_get_funcs: + * @paint: a rasterizer paint context. * - * Fetches the singleton #hb_paint_funcs_t that renders color glyphs - * into an #hb_raster_paint_t. Pass the #hb_raster_paint_t as the - * @paint_data argument when calling hb_font_paint_glyph(). + * Fetches the #hb_paint_funcs_t that renders color glyphs into + * @paint. Pass @paint as the @paint_data argument when calling + * hb_font_paint_glyph(). * * Return value: (transfer none): * The rasterizer paint functions * - * Since: 13.0.0 + * Since: 14.2.0 **/ hb_paint_funcs_t * -hb_raster_paint_get_funcs (void) +hb_raster_paint_get_funcs (const hb_raster_paint_t *paint HB_UNUSED) { return static_raster_paint_funcs.get_unconst (); } +static hb_bool_t +hb_raster_paint_glyph_impl (hb_raster_paint_t *paint, + hb_font_t *font, + hb_codepoint_t glyph, + hb_bool_t fallible) +{ + if (!paint->has_extents) + { + hb_glyph_extents_t ge; + if (hb_font_get_glyph_extents (font, glyph, &ge)) + hb_raster_paint_set_glyph_extents (paint, &ge); + } + + hb_paint_funcs_t *funcs = hb_raster_paint_get_funcs (paint); + hb_paint_push_transform (funcs, paint, + paint->base_transform.xx, paint->base_transform.yx, + paint->base_transform.xy, paint->base_transform.yy, + paint->base_transform.x0, paint->base_transform.y0); + + hb_bool_t ret = true; + if (fallible) + ret = hb_font_paint_glyph_or_fail (font, glyph, + funcs, paint, + paint->palette, paint->foreground); + else + hb_font_paint_glyph (font, glyph, + funcs, paint, + paint->palette, paint->foreground); + + hb_paint_pop_transform (funcs, paint); + return ret; +} + +/** + * hb_raster_paint_glyph_or_fail: + * @paint: a paint context + * @font: font to paint from + * @glyph: glyph ID to paint + * + * Convenience to paint one color glyph. Equivalent to: + * + * |[ + * hb_font_paint_glyph_or_fail (font, glyph, + * hb_raster_paint_get_funcs (paint), paint, + * palette, foreground); + * ]| + * + * Return value: `true` if painting succeeded, `false` otherwise. + * + * Since: 14.2.0 + **/ +hb_bool_t +hb_raster_paint_glyph_or_fail (hb_raster_paint_t *paint, + hb_font_t *font, + hb_codepoint_t glyph) +{ + return hb_raster_paint_glyph_impl (paint, font, glyph, true); +} + /** * hb_raster_paint_glyph: * @paint: a paint context * @font: font to paint from * @glyph: glyph ID to paint - * @pen_x: glyph origin x in font coordinates (pre-transform) - * @pen_y: glyph origin y in font coordinates (pre-transform) - * @palette: palette index - * @foreground: foreground color * - * Convenience wrapper to paint one color glyph at (@pen_x, @pen_y) using - * the paint context's current transform. The pen coordinates are applied - * before minification and transformed by the current affine transform. + * Paints one glyph into @paint. Unlike + * hb_raster_paint_glyph_or_fail(), glyphs with no color paint data + * fall back to a synthesized foreground-colored outline, so any + * glyph with an outline or bitmap image produces output. * - * Return value: `true` if painting succeeded, `false` otherwise. - * - * Since: 13.0.0 + * Since: 14.2.0 **/ -hb_bool_t +void hb_raster_paint_glyph (hb_raster_paint_t *paint, hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y, - unsigned palette, - hb_color_t foreground) + hb_codepoint_t glyph) { - float xx = paint->base_transform.xx; - float yx = paint->base_transform.yx; - float xy = paint->base_transform.xy; - float yy = paint->base_transform.yy; - float dx = paint->base_transform.x0; - float dy = paint->base_transform.y0; - - float tx = dx + xx * pen_x + xy * pen_y; - float ty = dy + yx * pen_x + yy * pen_y; - - if (!paint->has_extents) - { - hb_glyph_extents_t ge; - if (hb_font_get_glyph_extents (font, glyph, &ge)) - { - hb_raster_paint_set_transform (paint, xx, yx, xy, yy, tx, ty); - hb_raster_paint_set_glyph_extents (paint, &ge); - } - } - - hb_raster_paint_set_transform (paint, xx, yx, xy, yy, tx, ty); - paint->svg_glyph = glyph; - paint->svg_font = font; - paint->svg_palette = palette; - hb_bool_t ret = hb_font_paint_glyph_or_fail (font, glyph, - hb_raster_paint_get_funcs (), paint, - palette, foreground); - paint->svg_glyph = 0; - paint->svg_font = nullptr; - paint->svg_palette = 0; - hb_raster_paint_set_transform (paint, xx, yx, xy, yy, dx, dy); - return ret; + hb_raster_paint_glyph_impl (paint, font, glyph, false); } /** @@ -2007,11 +2285,14 @@ hb_raster_paint_glyph (hb_raster_paint_t *paint, hb_raster_image_t * hb_raster_paint_render (hb_raster_paint_t *paint) { - hb_raster_image_t *result = nullptr; + /* Common per-exit state reset. Runs on every return path, + * including the early-return failure cases below. */ + HB_SCOPE_GUARD (hb_raster_paint_clear (paint)); if (unlikely (!paint->has_extents)) - goto fail; + return nullptr; + hb_raster_image_t *result; if (paint->surface_stack.length) { result = paint->surface_stack[0]; @@ -2025,25 +2306,35 @@ hb_raster_paint_render (hb_raster_paint_t *paint) { result = paint->acquire_surface (); if (unlikely (!result)) - goto fail; + return nullptr; } - /* Clean up stacks and reset auto-extents for next glyph. */ - paint->transform_stack.clear (); - paint->release_all_clips (); - hb_raster_draw_reset (paint->clip_rdr); - paint->has_extents = false; - paint->fixed_extents = {}; - return result; +} -fail: +/** + * hb_raster_paint_clear: + * @paint: a paint context + * + * Discards accumulated paint output so @paint can be reused for + * another render. User configuration (base transform, scale + * factors, foreground, custom palette colors) is preserved. Call + * hb_raster_paint_reset() to also reset user configuration to + * defaults. + * + * Since: 14.2.0 + **/ +void +hb_raster_paint_clear (hb_raster_paint_t *paint) +{ + paint->fixed_extents = {}; + paint->has_extents = false; paint->transform_stack.clear (); paint->release_all_clips (); + for (auto *s : paint->surface_stack) + paint->release_surface (s); + paint->surface_stack.clear (); hb_raster_draw_reset (paint->clip_rdr); - paint->has_extents = false; - paint->fixed_extents = {}; - return nullptr; } /** @@ -2061,15 +2352,9 @@ hb_raster_paint_reset (hb_raster_paint_t *paint) paint->base_transform = {1, 0, 0, 1, 0, 0}; paint->x_scale_factor = 1.f; paint->y_scale_factor = 1.f; - paint->fixed_extents = {}; - paint->has_extents = false; paint->foreground = HB_COLOR (0, 0, 0, 255); hb_raster_paint_clear_custom_palette_colors (paint); - paint->transform_stack.clear (); - paint->release_all_clips (); - for (auto *s : paint->surface_stack) - paint->release_surface (s); - paint->surface_stack.clear (); + hb_raster_paint_clear (paint); } /** diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.hh index d5377259b2..7e3e9d0a25 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-paint.hh @@ -79,7 +79,22 @@ struct hb_raster_clip_t return ((int) x >= rect_x0 && (int) x < rect_x1 && (int) y >= rect_y0 && (int) y < rect_y1) ? 255 : 0; if (x >= width || y >= height) return 0; - return alpha[y * stride + x]; + if (stride < width) return 0; + if (height && stride > (size_t) -1 / height) return 0; + size_t idx = (size_t) y * stride + x; + if (!alpha.arrayZ || idx >= alpha.length) return 0; + return alpha[idx]; + } + + bool has_valid_alpha_mask () const + { + if (is_rect) + return true; + if (!alpha.arrayZ || stride < width) + return false; + if (height && stride > (size_t) -1 / height) + return false; + return (size_t) stride * height <= alpha.length; } }; @@ -96,13 +111,10 @@ struct hb_raster_paint_t hb_raster_extents_t fixed_extents = {}; bool has_extents = false; hb_color_t foreground = HB_COLOR (0, 0, 0, 255); + hb_color_t background = HB_COLOR (0, 0, 0, 0); + unsigned palette = 0; hb_map_t *custom_palette = nullptr; - /* SVG rendering state */ - hb_codepoint_t svg_glyph = 0; - hb_font_t *svg_font = nullptr; - unsigned svg_palette = 0; - /* Stacks */ hb_vector_t> transform_stack; hb_vector_t clip_stack; @@ -140,7 +152,8 @@ struct hb_raster_paint_t void release_surface (hb_raster_image_t *img) { - surface_cache.push (img); + if (!surface_cache.push_or_fail (img)) + hb_raster_image_destroy (img); } hb_raster_clip_t acquire_clip (unsigned w, unsigned h) @@ -152,6 +165,9 @@ struct hb_raster_paint_t clip.height = h; clip.stride = (w + 3u) & ~3u; clip.is_rect = false; + clip.rect_x0 = clip.rect_y0 = 0; + clip.rect_x1 = clip.rect_y1 = 0; + clip.min_x = clip.min_y = clip.max_x = clip.max_y = 0; return clip; } @@ -177,8 +193,10 @@ struct hb_raster_paint_t return clip_stack.tail (); } - hb_transform_t<> ¤t_transform () + hb_transform_t<> current_transform () { + if (unlikely (!transform_stack.length)) + return {1, 0, 0, 1, 0, 0}; return transform_stack.tail (); } @@ -198,6 +216,18 @@ struct hb_raster_paint_t apply_scale_factor (t); return t; } + + bool fetch_color_stops (hb_color_line_t *color_line) + { + unsigned count = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); + if (unlikely (!count || !scratch_color_stops.resize (count))) + { + scratch_color_stops.resize (0); + return false; + } + hb_color_line_get_color_stops (color_line, 0, &count, scratch_color_stops.arrayZ); + return true; + } }; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.cc deleted file mode 100644 index 760b9aea77..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.cc +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-base.hh" -#include "hb-raster-svg-parse.hh" - -void -svg_parse_style_props (hb_svg_str_t style, hb_svg_style_props_t *out) -{ - if (style.is_null ()) return; - const char *p = style.data; - const char *end = style.data + style.len; - while (p < end) - { - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ';')) - p++; - if (p >= end) break; - const char *name_start = p; - while (p < end && *p != ':' && *p != ';') - p++; - const char *name_end = p; - while (name_end > name_start && - (name_end[-1] == ' ' || name_end[-1] == '\t' || name_end[-1] == '\n' || name_end[-1] == '\r')) - name_end--; - if (p >= end || *p != ':') - { - while (p < end && *p != ';') p++; - continue; - } - p++; /* skip ':' */ - const char *value_start = p; - while (p < end && *p != ';') - p++; - const char *value_end = p; - while (value_start < value_end && - (*value_start == ' ' || *value_start == '\t' || *value_start == '\n' || *value_start == '\r')) - value_start++; - while (value_end > value_start && - (value_end[-1] == ' ' || value_end[-1] == '\t' || value_end[-1] == '\n' || value_end[-1] == '\r')) - value_end--; - - hb_svg_str_t prop_name = {name_start, (unsigned) (name_end - name_start)}; - hb_svg_str_t prop_value = {value_start, (unsigned) (value_end - value_start)}; - if (prop_name.len) - { - switch (hb_svg_ascii_lower (prop_name.data[0])) - { - case 'c': - if (prop_name.len == 9 && prop_name.eq_ascii_ci ("clip-path")) out->clip_path = prop_value; - else if (prop_name.len == 5 && prop_name.eq_ascii_ci ("color")) out->color = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("cx")) out->cx = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("cy")) out->cy = prop_value; - break; - case 'd': - if (prop_name.len == 7 && prop_name.eq_ascii_ci ("display")) out->display = prop_value; - else if (prop_name.len == 1 && prop_name.eq_ascii_ci ("d")) out->d = prop_value; - break; - case 'f': - if (prop_name.len == 4 && prop_name.eq_ascii_ci ("fill")) out->fill = prop_value; - else if (prop_name.len == 12 && prop_name.eq_ascii_ci ("fill-opacity")) out->fill_opacity = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("fx")) out->fx = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("fy")) out->fy = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("fr")) out->fr = prop_value; - break; - case 'g': - if ((prop_name.len == 13 && prop_name.eq_ascii_ci ("gradientunits")) || - (prop_name.len == 14 && prop_name.eq_ascii_ci ("gradient-units"))) out->gradient_units = prop_value; - else if ((prop_name.len == 17 && prop_name.eq_ascii_ci ("gradienttransform")) || - (prop_name.len == 18 && prop_name.eq_ascii_ci ("gradient-transform"))) out->gradient_transform = prop_value; - break; - case 'h': - if (prop_name.len == 6 && prop_name.eq_ascii_ci ("height")) out->height = prop_value; - break; - case 'o': - if (prop_name.len == 7 && prop_name.eq_ascii_ci ("opacity")) out->opacity = prop_value; - else if (prop_name.len == 6 && prop_name.eq_ascii_ci ("offset")) out->offset = prop_value; - break; - case 'p': - if (prop_name.len == 6 && prop_name.eq_ascii_ci ("points")) out->points = prop_value; - break; - case 'r': - if (prop_name.len == 1 && prop_name.eq_ascii_ci ("r")) out->r = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("rx")) out->rx = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("ry")) out->ry = prop_value; - break; - case 's': - if (prop_name.len == 10 && prop_name.eq_ascii_ci ("stop-color")) out->stop_color = prop_value; - else if (prop_name.len == 12 && prop_name.eq_ascii_ci ("stop-opacity")) out->stop_opacity = prop_value; - else if ((prop_name.len == 12 && prop_name.eq_ascii_ci ("spreadmethod")) || - (prop_name.len == 13 && prop_name.eq_ascii_ci ("spread-method"))) out->spread_method = prop_value; - break; - case 't': - if (prop_name.len == 9 && prop_name.eq_ascii_ci ("transform")) out->transform = prop_value; - break; - case 'v': - if (prop_name.len == 10 && prop_name.eq_ascii_ci ("visibility")) out->visibility = prop_value; - break; - case 'w': - if (prop_name.len == 5 && prop_name.eq_ascii_ci ("width")) out->width = prop_value; - break; - case 'x': - if (prop_name.len == 1 && prop_name.eq_ascii_ci ("x")) out->x = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("x1")) out->x1 = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("x2")) out->x2 = prop_value; - break; - case 'y': - if (prop_name.len == 1 && prop_name.eq_ascii_ci ("y")) out->y = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("y1")) out->y1 = prop_value; - else if (prop_name.len == 2 && prop_name.eq_ascii_ci ("y2")) out->y2 = prop_value; - break; - default: - break; - } - } - - if (p < end && *p == ';') p++; - } -} - -float -svg_parse_number_or_percent (hb_svg_str_t s, bool *is_percent) -{ - if (is_percent) *is_percent = false; - s = s.trim (); - if (!s.len) return 0.f; - if (s.data[s.len - 1] == '%') - { - if (is_percent) *is_percent = true; - hb_svg_str_t n = {s.data, s.len - 1}; - return n.to_float () / 100.f; - } - return s.to_float (); -} - -hb_svg_str_t -hb_raster_svg_find_href_attr (const hb_svg_xml_parser_t &parser) -{ - hb_svg_str_t href = parser.find_attr ("href"); - if (href.is_null ()) - href = parser.find_attr ("xlink:href"); - return href; -} - -bool -hb_raster_svg_parse_id_ref (hb_svg_str_t s, - hb_svg_str_t *out_id, - hb_svg_str_t *out_tail) -{ - if (out_id) *out_id = {}; - if (out_tail) *out_tail = {}; - s = s.trim (); - - if (s.len && s.data[0] == '#') - { - hb_svg_str_t id = {s.data + 1, s.len - 1}; - id = id.trim (); - if (!id.len) - return false; - if (out_id) *out_id = id; - return true; - } - - if (!s.starts_with_ascii_ci ("url(")) - return false; - - const char *p = s.data + 4; - const char *end = s.data + s.len; - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++; - - const char *q = p; - char quote = 0; - while (q < end) - { - char c = *q; - if (quote) - { - if (c == quote) quote = 0; - } - else - { - if (c == '"' || c == '\'') quote = c; - else if (c == ')') break; - } - q++; - } - if (q >= end || *q != ')') - return false; - - hb_svg_str_t id = {(const char *) p, (unsigned) (q - p)}; - id = id.trim (); - if (id.len >= 2 && - ((id.data[0] == '\'' && id.data[id.len - 1] == '\'') || - (id.data[0] == '"' && id.data[id.len - 1] == '"'))) - { - id.data++; - id.len -= 2; - } - id = id.trim (); - if (id.len && id.data[0] == '#') - { - id.data++; - id.len--; - } - id = id.trim (); - if (!id.len) - return false; - - if (out_id) *out_id = id; - if (out_tail) - { - const char *tail = q + 1; - while (tail < end && (*tail == ' ' || *tail == '\t' || *tail == '\n' || *tail == '\r')) tail++; - *out_tail = {(const char *) tail, (unsigned) (end - tail)}; - } - return true; -} - -bool -hb_raster_svg_parse_local_id_ref (hb_svg_str_t s, - hb_svg_str_t *out_id, - hb_svg_str_t *out_tail) -{ - if (out_id) *out_id = {}; - if (out_tail) *out_tail = {}; - s = s.trim (); - - if (s.len && s.data[0] == '#') - { - hb_svg_str_t id = {s.data + 1, s.len - 1}; - id = id.trim (); - if (!id.len) - return false; - if (out_id) *out_id = id; - return true; - } - - if (!s.starts_with_ascii_ci ("url(")) - return false; - - hb_svg_str_t id; - if (!hb_raster_svg_parse_id_ref (s, &id, out_tail)) - return false; - - const char *p = s.data + 4; - const char *end = s.data + s.len; - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++; - if (p < end && (*p == '\'' || *p == '"')) - { - p++; - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++; - if (p >= end || *p != '#') - return false; - } - else if (p >= end || *p != '#') - return false; - - if (out_id) *out_id = id; - return true; -} - -bool -hb_raster_svg_find_element_by_id (const char *doc_start, - unsigned doc_len, - const OT::SVG::accelerator_t *svg_accel, - const OT::SVG::svg_doc_cache_t *doc_cache, - hb_svg_str_t id, - const char **found) -{ - *found = nullptr; - if (!doc_start || !doc_len || !id.len) - return false; - - if (doc_cache && svg_accel) - { - unsigned start = 0, end = 0; - OT::SVG::svg_id_span_t key = {id.data, id.len}; - if (svg_accel->doc_cache_find_id_span (doc_cache, key, &start, &end)) - { - if (start < doc_len && end <= doc_len && start < end) - { - *found = doc_start + start; - return true; - } - } - } - - hb_svg_xml_parser_t search (doc_start, doc_len); - while (true) - { - hb_svg_token_type_t tok = search.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok != SVG_TOKEN_OPEN_TAG && tok != SVG_TOKEN_SELF_CLOSE_TAG) continue; - hb_svg_str_t attr_id = search.find_attr ("id"); - if (attr_id.len == id.len && 0 == memcmp (attr_id.data, id.data, id.len)) - { - *found = search.tag_start; - return true; - } - } - return false; -} - -bool -hb_raster_svg_parse_viewbox (hb_svg_str_t viewbox_str, - float *x, - float *y, - float *w, - float *h) -{ - if (!viewbox_str.len) - return false; - hb_svg_float_parser_t vb_fp (viewbox_str); - float vb_x = vb_fp.next_float (); - float vb_y = vb_fp.next_float (); - float vb_w = vb_fp.next_float (); - float vb_h = vb_fp.next_float (); - if (vb_w <= 0.f || vb_h <= 0.f) - return false; - if (x) *x = vb_x; - if (y) *y = vb_y; - if (w) *w = vb_w; - if (h) *h = vb_h; - return true; -} - -static inline float -svg_align_offset (hb_svg_str_t align, - float leftover, - char axis) -{ - if (leftover <= 0.f) return 0.f; - if ((axis == 'x' && align.starts_with_ascii_ci ("xMin")) || - (axis == 'y' && (align.eq_ascii_ci ("xMinYMin") || - align.eq_ascii_ci ("xMidYMin") || - align.eq_ascii_ci ("xMaxYMin")))) - return 0.f; - if ((axis == 'x' && align.starts_with_ascii_ci ("xMax")) || - (axis == 'y' && (align.eq_ascii_ci ("xMinYMax") || - align.eq_ascii_ci ("xMidYMax") || - align.eq_ascii_ci ("xMaxYMax")))) - return leftover; - return leftover * 0.5f; -} - -bool -hb_raster_svg_compute_viewbox_transform (float viewport_w, - float viewport_h, - float vb_x, - float vb_y, - float vb_w, - float vb_h, - hb_svg_str_t preserve_aspect_ratio, - hb_svg_transform_t *out) -{ - if (!(viewport_w > 0.f && viewport_h > 0.f && vb_w > 0.f && vb_h > 0.f)) - return false; - - hb_svg_str_t par = preserve_aspect_ratio.trim (); - if (par.starts_with_ascii_ci ("defer")) - { - const char *p = par.data + 5; - const char *end = par.data + par.len; - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++; - par = hb_svg_str_t (p, (unsigned) (end - p)); - } - if (!par.len) - par = hb_svg_str_t ("xMidYMid meet", 12); - - bool is_none = false; - bool is_slice = false; - hb_svg_str_t align = par; - const char *p = par.data; - const char *end = par.data + par.len; - while (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') p++; - align = hb_svg_str_t (par.data, (unsigned) (p - par.data)).trim (); - - if (par.starts_with_ascii_ci ("none")) - is_none = true; - else if (align.starts_with_ascii_ci ("x")) - { - const char *mode = p; - while (mode < end && (*mode == ' ' || *mode == '\t' || *mode == '\n' || *mode == '\r')) mode++; - if (mode < end && hb_svg_str_t (mode, (unsigned) (end - mode)).starts_with_ascii_ci ("slice")) - is_slice = true; - } - - hb_svg_transform_t t; - if (is_none) - { - t.xx = viewport_w / vb_w; - t.yy = viewport_h / vb_h; - t.dx = -vb_x * t.xx; - t.dy = -vb_y * t.yy; - *out = t; - return true; - } - - float sx = viewport_w / vb_w; - float sy = viewport_h / vb_h; - float s = is_slice ? hb_max (sx, sy) : hb_min (sx, sy); - float scaled_w = vb_w * s; - float scaled_h = vb_h * s; - float leftover_x = viewport_w - scaled_w; - float leftover_y = viewport_h - scaled_h; - - if (!align.starts_with_ascii_ci ("x")) - align = hb_svg_str_t ("xMidYMid", 8); - - t.xx = s; - t.yy = s; - t.dx = svg_align_offset (align, leftover_x, 'x') - vb_x * s; - t.dy = svg_align_offset (align, leftover_y, 'y') - vb_y * s; - *out = t; - return true; -} - -bool -hb_raster_svg_compute_use_target_viewbox_transform (hb_svg_xml_parser_t &target_parser, - float use_w, - float use_h, - hb_svg_transform_t *out) -{ - if (!(target_parser.tag_name.eq ("svg") || target_parser.tag_name.eq ("symbol"))) - return false; - - float viewport_w = use_w; - float viewport_h = use_h; - hb_svg_style_props_t target_style_props; - svg_parse_style_props (target_parser.find_attr ("style"), &target_style_props); - if (viewport_w <= 0.f) - viewport_w = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (target_parser, target_style_props.width, "width")); - if (viewport_h <= 0.f) - viewport_h = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (target_parser, target_style_props.height, "height")); - - float vb_x = 0.f, vb_y = 0.f, vb_w = 0.f, vb_h = 0.f; - if (!hb_raster_svg_parse_viewbox (target_parser.find_attr ("viewBox"), &vb_x, &vb_y, &vb_w, &vb_h)) - return false; - - if (!(viewport_w > 0.f && viewport_h > 0.f)) - { - viewport_w = vb_w; - viewport_h = vb_h; - } - - return hb_raster_svg_compute_viewbox_transform (viewport_w, viewport_h, vb_x, vb_y, vb_w, vb_h, - target_parser.find_attr ("preserveAspectRatio"), - out); -} - -void -hb_raster_svg_parse_use_geometry (hb_svg_xml_parser_t &parser, - float *x, - float *y, - float *w, - float *h) -{ - hb_svg_style_props_t style_props; - svg_parse_style_props (parser.find_attr ("style"), &style_props); - - if (x) *x = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, style_props.x, "x")); - if (y) *y = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, style_props.y, "y")); - if (w) *w = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, style_props.width, "width")); - if (h) *h = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, style_props.height, "height")); -} - -float -hb_raster_svg_parse_non_percent_length (hb_svg_str_t s) -{ - bool is_percent = false; - float v = svg_parse_number_or_percent (s, &is_percent); - return is_percent ? 0.f : v; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.hh deleted file mode 100644 index c7bdc9bd2f..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-base.hh +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_BASE_HH -#define HB_RASTER_SVG_BASE_HH - -#include "hb.hh" -#include "OT/Color/svg/svg.hh" - -#include -#include -#include - -static inline char -hb_svg_ascii_lower (char c) -{ - if (c >= 'A' && c <= 'Z') - return c + ('a' - 'A'); - return c; -} - -struct hb_svg_str_t -{ - const char *data; - unsigned len; - - hb_svg_str_t () : data (nullptr), len (0) {} - hb_svg_str_t (const char *d, unsigned l) : data (d), len (l) {} - - bool is_null () const { return !data; } - - bool eq (const char *s) const - { - unsigned slen = (unsigned) strlen (s); - return len == slen && memcmp (data, s, len) == 0; - } - - bool starts_with (const char *prefix) const - { - unsigned plen = (unsigned) strlen (prefix); - return len >= plen && memcmp (data, prefix, plen) == 0; - } - - bool eq_ascii_ci (const char *lit) const - { - unsigned n = (unsigned) strlen (lit); - if (len != n) return false; - for (unsigned i = 0; i < n; i++) - if (hb_svg_ascii_lower (data[i]) != hb_svg_ascii_lower (lit[i])) - return false; - return true; - } - - bool starts_with_ascii_ci (const char *lit) const - { - unsigned n = (unsigned) strlen (lit); - if (len < n) return false; - for (unsigned i = 0; i < n; i++) - if (hb_svg_ascii_lower (data[i]) != hb_svg_ascii_lower (lit[i])) - return false; - return true; - } - - float to_float () const - { - if (!data || !len) return 0.f; - char buf[64]; - unsigned n = hb_min (len, (unsigned) sizeof (buf) - 1); - memcpy (buf, data, n); - buf[n] = '\0'; - float v = strtof (buf, nullptr); - return isfinite (v) ? v : 0.f; - } - - hb_svg_str_t trim_left () const - { - const char *p = data; - unsigned l = len; - while (l && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) - { - p++; - l--; - } - return {p, l}; - } - - hb_svg_str_t trim () const - { - hb_svg_str_t s = trim_left (); - while (s.len && (s.data[s.len - 1] == ' ' || s.data[s.len - 1] == '\t' || - s.data[s.len - 1] == '\n' || s.data[s.len - 1] == '\r')) - s.len--; - return s; - } -}; - -struct hb_svg_style_props_t -{ - hb_svg_str_t fill; - hb_svg_str_t fill_opacity; - hb_svg_str_t opacity; - hb_svg_str_t transform; - hb_svg_str_t clip_path; - hb_svg_str_t display; - hb_svg_str_t color; - hb_svg_str_t visibility; - hb_svg_str_t offset; - hb_svg_str_t stop_color; - hb_svg_str_t stop_opacity; - hb_svg_str_t spread_method; - hb_svg_str_t gradient_units; - hb_svg_str_t gradient_transform; - hb_svg_str_t x; - hb_svg_str_t y; - hb_svg_str_t width; - hb_svg_str_t height; - hb_svg_str_t cx; - hb_svg_str_t cy; - hb_svg_str_t r; - hb_svg_str_t fx; - hb_svg_str_t fy; - hb_svg_str_t fr; - hb_svg_str_t rx; - hb_svg_str_t ry; - hb_svg_str_t x1; - hb_svg_str_t y1; - hb_svg_str_t x2; - hb_svg_str_t y2; - hb_svg_str_t points; - hb_svg_str_t d; -}; - -struct hb_svg_xml_parser_t; -struct hb_svg_transform_t; - -HB_INTERNAL void svg_parse_style_props (hb_svg_str_t style, hb_svg_style_props_t *out); -HB_INTERNAL float svg_parse_number_or_percent (hb_svg_str_t s, bool *is_percent); -HB_INTERNAL hb_svg_str_t hb_raster_svg_find_href_attr (const hb_svg_xml_parser_t &parser); -HB_INTERNAL bool hb_raster_svg_parse_id_ref (hb_svg_str_t s, - hb_svg_str_t *out_id, - hb_svg_str_t *out_tail); -HB_INTERNAL bool hb_raster_svg_parse_local_id_ref (hb_svg_str_t s, - hb_svg_str_t *out_id, - hb_svg_str_t *out_tail); -HB_INTERNAL bool hb_raster_svg_find_element_by_id (const char *doc_start, - unsigned doc_len, - const OT::SVG::accelerator_t *svg_accel, - const OT::SVG::svg_doc_cache_t *doc_cache, - hb_svg_str_t id, - const char **found); -HB_INTERNAL bool hb_raster_svg_parse_viewbox (hb_svg_str_t viewbox_str, - float *x, - float *y, - float *w, - float *h); -HB_INTERNAL bool hb_raster_svg_compute_viewbox_transform (float viewport_w, - float viewport_h, - float vb_x, - float vb_y, - float vb_w, - float vb_h, - hb_svg_str_t preserve_aspect_ratio, - hb_svg_transform_t *out); -HB_INTERNAL bool hb_raster_svg_compute_use_target_viewbox_transform (hb_svg_xml_parser_t &target_parser, - float use_w, - float use_h, - hb_svg_transform_t *out); -HB_INTERNAL void hb_raster_svg_parse_use_geometry (hb_svg_xml_parser_t &parser, - float *x, - float *y, - float *w, - float *h); -HB_INTERNAL float hb_raster_svg_parse_non_percent_length (hb_svg_str_t s); -static inline float -svg_parse_float_clamped01 (hb_svg_str_t s) -{ - return hb_clamp (s.to_float (), 0.f, 1.f); -} - -static inline bool -svg_str_is_inherit (hb_svg_str_t s) -{ - return s.trim ().eq_ascii_ci ("inherit"); -} - -static inline bool -svg_str_is_none (hb_svg_str_t s) -{ - return s.trim ().eq_ascii_ci ("none"); -} - -static inline bool -hb_raster_svg_tag_is_container (hb_svg_str_t tag) -{ - return tag.eq ("g") || tag.eq ("a") || tag.eq ("svg") || tag.eq ("symbol"); -} - -static inline bool -hb_raster_svg_tag_is_container_or_use (hb_svg_str_t tag) -{ - return hb_raster_svg_tag_is_container (tag) || tag.eq ("use"); -} - -#endif /* HB_RASTER_SVG_BASE_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.cc deleted file mode 100644 index 2bc39b63b9..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.cc +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-bbox.hh" - -static void -svg_bbox_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *draw_data, - hb_draw_state_t *st HB_UNUSED, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - ((hb_extents_t<> *) draw_data)->add_point (to_x, to_y); -} - -static void -svg_bbox_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *draw_data, - hb_draw_state_t *st HB_UNUSED, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - ((hb_extents_t<> *) draw_data)->add_point (to_x, to_y); -} - -static void -svg_bbox_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *draw_data, - hb_draw_state_t *st HB_UNUSED, - float control_x, float control_y, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t<> *ext = (hb_extents_t<> *) draw_data; - ext->add_point (control_x, control_y); - ext->add_point (to_x, to_y); -} - -static void -svg_bbox_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, - void *draw_data, - hb_draw_state_t *st HB_UNUSED, - float control1_x, float control1_y, - float control2_x, float control2_y, - float to_x, float to_y, - void *user_data HB_UNUSED) -{ - hb_extents_t<> *ext = (hb_extents_t<> *) draw_data; - ext->add_point (control1_x, control1_y); - ext->add_point (control2_x, control2_y); - ext->add_point (to_x, to_y); -} - -static hb_draw_funcs_t * -svg_bbox_draw_funcs () -{ - static hb_draw_funcs_t *funcs = nullptr; - if (unlikely (!funcs)) - { - funcs = hb_draw_funcs_create (); - hb_draw_funcs_set_move_to_func (funcs, svg_bbox_move_to, nullptr, nullptr); - hb_draw_funcs_set_line_to_func (funcs, svg_bbox_line_to, nullptr, nullptr); - hb_draw_funcs_set_quadratic_to_func (funcs, svg_bbox_quadratic_to, nullptr, nullptr); - hb_draw_funcs_set_cubic_to_func (funcs, svg_bbox_cubic_to, nullptr, nullptr); - hb_draw_funcs_make_immutable (funcs); - } - return funcs; -} - -bool -hb_raster_svg_compute_shape_bbox (const hb_svg_shape_emit_data_t &shape, - hb_extents_t<> *bbox) -{ - hb_extents_t<> ext; - hb_svg_shape_emit_data_t tmp = shape; - hb_raster_svg_shape_path_emit (svg_bbox_draw_funcs (), &ext, &tmp); - if (ext.is_empty ()) return false; - *bbox = ext; - return true; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.hh deleted file mode 100644 index 46802e6d7a..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-bbox.hh +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_BBOX_HH -#define HB_RASTER_SVG_BBOX_HH - -#include "hb.hh" - -#include "hb-geometry.hh" -#include "hb-raster-svg-parse.hh" - -HB_INTERNAL bool -hb_raster_svg_compute_shape_bbox (const hb_svg_shape_emit_data_t &shape, - hb_extents_t<> *bbox); - -#endif /* HB_RASTER_SVG_BBOX_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.cc deleted file mode 100644 index 175e871150..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.cc +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-clip.hh" - -#include "hb-raster.h" -#include "hb-raster-paint.hh" -#include "hb-raster-svg.hh" -#include "hb-raster-svg-base.hh" -#include "hb-decycler.hh" - -#include - -static inline bool -svg_transform_is_identity (const hb_svg_transform_t &t) -{ - return t.xx == 1.f && t.yx == 0.f && - t.xy == 0.f && t.yy == 1.f && - t.dx == 0.f && t.dy == 0.f; -} - -static bool -svg_parse_element_transform (hb_svg_xml_parser_t &parser, - hb_svg_transform_t *out) -{ - hb_svg_style_props_t style_props; - svg_parse_style_props (parser.find_attr ("style"), &style_props); - hb_svg_str_t transform = svg_pick_attr_or_style (parser, style_props.transform, "transform"); - if (!transform.len) - return false; - hb_raster_svg_parse_transform (transform, out); - return true; -} - -struct hb_svg_clip_collect_context_t -{ - hb_svg_defs_t *defs; - hb_svg_clip_path_def_t *clip; - const char *doc_start; - unsigned doc_len; - const OT::SVG::accelerator_t *svg_accel; - const OT::SVG::svg_doc_cache_t *doc_cache; - hb_decycler_t *use_decycler; - bool *had_alloc_failure; -}; - -static inline void -svg_clip_append_shape (hb_svg_clip_collect_context_t *ctx, - const hb_svg_shape_emit_data_t &shape, - const hb_svg_transform_t &transform) -{ - hb_svg_clip_shape_t clip_shape; - clip_shape.shape = shape; - if (!svg_transform_is_identity (transform)) - { - clip_shape.has_transform = true; - clip_shape.transform = transform; - } - ctx->defs->clip_shapes.push (clip_shape); - if (likely (!ctx->defs->clip_shapes.in_error ())) - ctx->clip->shape_count++; - else if (ctx->had_alloc_failure) - *ctx->had_alloc_failure = true; -} - -static void -svg_skip_subtree (hb_svg_xml_parser_t &parser) -{ - int depth = 1; - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_CLOSE_TAG) depth--; - else if (tok == SVG_TOKEN_OPEN_TAG) depth++; - } -} - -static inline bool -svg_resolve_element_visibility (hb_svg_xml_parser_t &parser, - bool parent_visible) -{ - hb_svg_style_props_t style_props; - svg_parse_style_props (parser.find_attr ("style"), &style_props); - hb_svg_str_t display_str = svg_pick_attr_or_style (parser, style_props.display, "display"); - hb_svg_str_t visibility_str = svg_pick_attr_or_style (parser, style_props.visibility, "visibility"); - if (display_str.trim ().eq_ascii_ci ("none")) - return false; - hb_svg_str_t vis_trim = visibility_str.trim (); - if (!vis_trim.len || vis_trim.eq_ascii_ci ("inherit")) - return parent_visible; - if (vis_trim.eq_ascii_ci ("hidden") || - vis_trim.eq_ascii_ci ("collapse")) - return false; - if (vis_trim.eq_ascii_ci ("visible")) - return true; - return parent_visible; -} - -static void -svg_clip_collect_ref_element (hb_svg_clip_collect_context_t *ctx, - hb_svg_xml_parser_t &parser, - const hb_svg_transform_t &base_transform, - unsigned depth, - bool suppress_viewbox_once = false, - bool parent_visible = true, - bool allow_symbol_once = false); - -static void -svg_clip_collect_use_target (hb_svg_clip_collect_context_t *ctx, - hb_svg_xml_parser_t &use_parser, - const hb_svg_transform_t &base_transform, - unsigned depth) -{ - const unsigned SVG_MAX_CLIP_USE_DEPTH = 64; - if (depth >= SVG_MAX_CLIP_USE_DEPTH) - return; - - hb_svg_str_t href = hb_raster_svg_find_href_attr (use_parser); - hb_svg_str_t ref_id; - if (!hb_raster_svg_parse_local_id_ref (href, &ref_id, nullptr)) - return; - - const char *found = nullptr; - if (!hb_raster_svg_find_element_by_id (ctx->doc_start, ctx->doc_len, - ctx->svg_accel, ctx->doc_cache, - ref_id, &found)) - return; - - hb_decycler_node_t node (*ctx->use_decycler); - if (unlikely (!node.visit ((uintptr_t) found))) - return; - - hb_svg_transform_t effective = base_transform; - float use_x = 0.f, use_y = 0.f, use_w = 0.f, use_h = 0.f; - hb_raster_svg_parse_use_geometry (use_parser, &use_x, &use_y, &use_w, &use_h); - if (use_x != 0.f || use_y != 0.f) - { - hb_svg_transform_t tr; - tr.dx = use_x; - tr.dy = use_y; - effective.multiply (tr); - } - - unsigned remaining = ctx->doc_len - (unsigned) (found - ctx->doc_start); - hb_svg_xml_parser_t ref_parser (found, remaining); - hb_svg_token_type_t rt = ref_parser.next (); - if (rt != SVG_TOKEN_OPEN_TAG && rt != SVG_TOKEN_SELF_CLOSE_TAG) - return; - - bool viewport_mapped = false; - hb_svg_transform_t vb_t; - if (hb_raster_svg_compute_use_target_viewbox_transform (ref_parser, use_w, use_h, &vb_t)) - { - effective.multiply (vb_t); - viewport_mapped = true; - } - - bool allow_symbol = ref_parser.tag_name.eq ("symbol"); - svg_clip_collect_ref_element (ctx, ref_parser, effective, depth + 1, - viewport_mapped, true, allow_symbol); -} - -static void -svg_clip_collect_ref_element (hb_svg_clip_collect_context_t *ctx, - hb_svg_xml_parser_t &parser, - const hb_svg_transform_t &base_transform, - unsigned depth, - bool suppress_viewbox_once, - bool parent_visible, - bool allow_symbol_once) -{ - const unsigned SVG_MAX_CLIP_REF_DEPTH = 64; - if (depth >= SVG_MAX_CLIP_REF_DEPTH) - { - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - - bool is_visible = svg_resolve_element_visibility (parser, parent_visible); - if (!is_visible) - { - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - - /* Definitions are not directly renderable clip geometry. */ - if (parser.tag_name.eq ("defs")) - { - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - if (parser.tag_name.eq ("symbol") && !allow_symbol_once) - { - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - if (parser.tag_name.eq ("symbol")) - allow_symbol_once = false; - - hb_svg_transform_t effective = base_transform; - hb_svg_style_props_t geom_style_props; - svg_parse_style_props (parser.find_attr ("style"), &geom_style_props); - hb_svg_transform_t local_t; - if (svg_parse_element_transform (parser, &local_t)) - effective.multiply (local_t); - if (parser.tag_name.eq ("svg")) - { - float svg_x = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.x, "x")); - float svg_y = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.y, "y")); - if (svg_x != 0.f || svg_y != 0.f) - { - hb_svg_transform_t tr; - tr.dx = svg_x; - tr.dy = svg_y; - effective.multiply (tr); - } - - if (!suppress_viewbox_once) - { - float vb_x = 0.f, vb_y = 0.f, vb_w = 0.f, vb_h = 0.f; - if (hb_raster_svg_parse_viewbox (parser.find_attr ("viewBox"), - &vb_x, &vb_y, &vb_w, &vb_h)) - { - float viewport_w = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.width, "width")); - float viewport_h = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.height, "height")); - if (!(viewport_w > 0.f && viewport_h > 0.f)) - { - viewport_w = vb_w; - viewport_h = vb_h; - } - hb_svg_transform_t vb_t; - if (hb_raster_svg_compute_viewbox_transform (viewport_w, viewport_h, - vb_x, vb_y, vb_w, vb_h, - parser.find_attr ("preserveAspectRatio"), - &vb_t)) - effective.multiply (vb_t); - } - suppress_viewbox_once = false; - } - } - - hb_svg_shape_emit_data_t shape; - if (hb_raster_svg_parse_shape_tag (parser, &shape)) - { - svg_clip_append_shape (ctx, shape, effective); - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - - if (parser.tag_name.eq ("use")) - { - svg_clip_collect_use_target (ctx, parser, effective, depth + 1); - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - - bool is_container = hb_raster_svg_tag_is_container (parser.tag_name); - if (!is_container || parser.self_closing) - { - if (!parser.self_closing) - svg_skip_subtree (parser); - return; - } - - int inner_depth = 1; - while (inner_depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_CLOSE_TAG) - { - inner_depth--; - continue; - } - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - svg_clip_collect_ref_element (ctx, parser, effective, depth + 1, false, is_visible, false); - } -} - -void -hb_raster_svg_process_clip_path_def (hb_svg_defs_t *defs, - hb_svg_xml_parser_t &parser, - hb_svg_token_type_t tok, - const char *doc_start, - unsigned doc_len, - const OT::SVG::accelerator_t *svg_accel, - const OT::SVG::svg_doc_cache_t *doc_cache) -{ - hb_svg_clip_path_def_t clip; - hb_svg_str_t id = parser.find_attr ("id"); - hb_svg_str_t units = parser.find_attr ("clipPathUnits").trim (); - if (units.eq_ascii_ci ("objectBoundingBox")) - clip.units_user_space = false; - else if (units.eq_ascii_ci ("userSpaceOnUse")) - clip.units_user_space = true; - else - clip.units_user_space = true; - - hb_svg_transform_t cp_t; - if (svg_parse_element_transform (parser, &cp_t)) - { - clip.has_clip_transform = true; - clip.clip_transform = cp_t; - } - - clip.first_shape = defs->clip_shapes.length; - clip.shape_count = 0; - - if (tok == SVG_TOKEN_OPEN_TAG) - { - const unsigned SVG_MAX_CLIP_DEPTH = 64; - hb_svg_transform_t inherited[SVG_MAX_CLIP_DEPTH]; - bool inherited_visibility[SVG_MAX_CLIP_DEPTH]; - inherited[0] = hb_svg_transform_t (); - inherited[1] = hb_svg_transform_t (); - inherited_visibility[0] = true; - inherited_visibility[1] = true; - hb_decycler_t use_decycler; - - int cdepth = 1; - bool had_alloc_failure = false; - hb_svg_clip_collect_context_t collect_ctx = { - defs, &clip, - doc_start, doc_len, svg_accel, doc_cache, - &use_decycler, &had_alloc_failure - }; - while (cdepth > 0) - { - hb_svg_token_type_t ct = parser.next (); - if (ct == SVG_TOKEN_EOF) break; - if (ct == SVG_TOKEN_CLOSE_TAG) { cdepth--; continue; } - if (ct == SVG_TOKEN_OPEN_TAG || ct == SVG_TOKEN_SELF_CLOSE_TAG) - { - if (parser.tag_name.eq ("symbol")) - { - if (ct == SVG_TOKEN_OPEN_TAG) - { - int skip_depth = 1; - while (skip_depth > 0) - { - hb_svg_token_type_t st = parser.next (); - if (st == SVG_TOKEN_EOF) break; - if (st == SVG_TOKEN_CLOSE_TAG) skip_depth--; - else if (st == SVG_TOKEN_OPEN_TAG) skip_depth++; - } - } - continue; - } - - if (parser.tag_name.eq ("defs")) - { - if (ct == SVG_TOKEN_OPEN_TAG) - { - int skip_depth = 1; - while (skip_depth > 0) - { - hb_svg_token_type_t st = parser.next (); - if (st == SVG_TOKEN_EOF) break; - if (st == SVG_TOKEN_CLOSE_TAG) skip_depth--; - else if (st == SVG_TOKEN_OPEN_TAG) skip_depth++; - } - } - continue; - } - - bool parent_visible = (unsigned) cdepth < SVG_MAX_CLIP_DEPTH - ? inherited_visibility[cdepth] - : true; - bool is_visible = svg_resolve_element_visibility (parser, parent_visible); - bool is_hidden = !is_visible; - if (is_hidden) - { - if (ct == SVG_TOKEN_OPEN_TAG) - { - int skip_depth = 1; - while (skip_depth > 0) - { - hb_svg_token_type_t st = parser.next (); - if (st == SVG_TOKEN_EOF) break; - if (st == SVG_TOKEN_CLOSE_TAG) skip_depth--; - else if (st == SVG_TOKEN_OPEN_TAG) skip_depth++; - } - } - continue; - } - - hb_svg_transform_t effective = (unsigned) cdepth < SVG_MAX_CLIP_DEPTH - ? inherited[cdepth] - : hb_svg_transform_t (); - - hb_svg_transform_t local; - bool has_local_transform = svg_parse_element_transform (parser, &local); - if (has_local_transform) - { - effective.multiply (local); - } - - if (parser.tag_name.eq ("use")) - { - svg_clip_collect_use_target (&collect_ctx, parser, effective, 0); - } - else - { - hb_svg_shape_emit_data_t shape; - if (hb_raster_svg_parse_shape_tag (parser, &shape)) - svg_clip_append_shape (&collect_ctx, shape, effective); - } - - if (ct == SVG_TOKEN_OPEN_TAG) - { - if ((unsigned) (cdepth + 1) < SVG_MAX_CLIP_DEPTH) - { - inherited[cdepth + 1] = effective; - inherited_visibility[cdepth + 1] = is_visible; - } - cdepth++; - } - } - } - if (had_alloc_failure) - id = {}; - } - - if (id.len) - (void) defs->add_clip_path (hb_bytes_t (id.data, id.len), clip); -} - -struct hb_svg_clip_emit_data_t -{ - const hb_svg_defs_t *defs; - const hb_svg_clip_path_def_t *clip; - hb_transform_t<> base_transform; - hb_transform_t<> bbox_transform; - bool has_bbox_transform = false; -}; - -static inline hb_transform_t<> -svg_to_hb_transform (const hb_svg_transform_t &t) -{ - return hb_transform_t<> (t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); -} - -static void -svg_clip_path_emit (hb_draw_funcs_t *dfuncs, - void *draw_data, - void *user_data) -{ - hb_raster_draw_t *rdr = (hb_raster_draw_t *) draw_data; - hb_svg_clip_emit_data_t *ed = (hb_svg_clip_emit_data_t *) user_data; - const hb_svg_clip_path_def_t *clip = ed->clip; - - for (unsigned i = 0; i < clip->shape_count; i++) - { - const hb_svg_clip_shape_t &s = ed->defs->clip_shapes[clip->first_shape + i]; - hb_transform_t<> t = ed->base_transform; - if (ed->has_bbox_transform) - t.multiply (ed->bbox_transform); - if (clip->has_clip_transform) - t.multiply (svg_to_hb_transform (clip->clip_transform)); - if (s.has_transform) - t.multiply (svg_to_hb_transform (s.transform)); - - hb_raster_draw_set_transform (rdr, t.xx, t.yx, t.xy, t.yy, t.x0, t.y0); - - hb_svg_shape_emit_data_t shape = s.shape; - hb_raster_svg_shape_path_emit (dfuncs, draw_data, &shape); - } -} - -bool -hb_raster_svg_push_clip_path_ref (hb_raster_paint_t *paint, - hb_svg_defs_t *defs, - hb_svg_str_t clip_path_str, - const hb_extents_t<> *object_bbox) -{ - if (clip_path_str.is_null ()) return false; - hb_svg_str_t trimmed = clip_path_str.trim (); - if (!trimmed.len || trimmed.eq_ascii_ci ("none")) return false; - - hb_svg_str_t clip_id; - if (!hb_raster_svg_parse_local_id_ref (trimmed, &clip_id, nullptr)) - return false; - - const hb_svg_clip_path_def_t *clip = defs->find_clip_path (hb_bytes_t (clip_id.data, clip_id.len)); - if (!clip) return false; - - hb_svg_clip_emit_data_t ed; - ed.defs = defs; - ed.clip = clip; - ed.base_transform = paint->current_effective_transform (); - - if (!clip->units_user_space) - { - if (!object_bbox || object_bbox->is_empty ()) - return false; - float w = object_bbox->xmax - object_bbox->xmin; - float h = object_bbox->ymax - object_bbox->ymin; - if (!(isfinite (w) && isfinite (h)) || w <= 0.f || h <= 0.f) - return false; - ed.has_bbox_transform = true; - ed.bbox_transform = hb_transform_t<> (w, 0, 0, h, object_bbox->xmin, object_bbox->ymin); - } - - hb_raster_paint_push_clip_path (paint, svg_clip_path_emit, &ed); - return true; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.hh deleted file mode 100644 index 0b89cc8f0d..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-clip.hh +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_CLIP_HH -#define HB_RASTER_SVG_CLIP_HH - -#include "hb.hh" - -#include "OT/Color/svg/svg.hh" -#include "hb-paint.hh" -#include "hb-raster-svg-defs.hh" - -struct hb_raster_paint_t; - -HB_INTERNAL void -hb_raster_svg_process_clip_path_def (hb_svg_defs_t *defs, - hb_svg_xml_parser_t &parser, - hb_svg_token_type_t tok, - const char *doc_start, - unsigned doc_len, - const OT::SVG::accelerator_t *svg_accel, - const OT::SVG::svg_doc_cache_t *doc_cache); - -HB_INTERNAL bool -hb_raster_svg_push_clip_path_ref (hb_raster_paint_t *paint, - hb_svg_defs_t *defs, - hb_svg_str_t clip_path_str, - const hb_extents_t<> *object_bbox); - -#endif /* HB_RASTER_SVG_CLIP_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.cc deleted file mode 100644 index a13634dd4b..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.cc +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-color.hh" - -#include "hb-raster.h" -#include "hb-raster-svg-base.hh" -#include "hb-ot-color.h" - -#include -#include - -struct hb_svg_named_color_t -{ - const char *name; - uint32_t rgb; /* 0xRRGGBB */ -}; - -static const hb_svg_named_color_t svg_named_colors[] = { - {"aliceblue", 0xF0F8FF}, - {"antiquewhite", 0xFAEBD7}, - {"aqua", 0x00FFFF}, - {"aquamarine", 0x7FFFD4}, - {"azure", 0xF0FFFF}, - {"beige", 0xF5F5DC}, - {"bisque", 0xFFE4C4}, - {"black", 0x000000}, - {"blanchedalmond", 0xFFEBCD}, - {"blue", 0x0000FF}, - {"blueviolet", 0x8A2BE2}, - {"brown", 0xA52A2A}, - {"burlywood", 0xDEB887}, - {"cadetblue", 0x5F9EA0}, - {"chartreuse", 0x7FFF00}, - {"chocolate", 0xD2691E}, - {"coral", 0xFF7F50}, - {"cornflowerblue", 0x6495ED}, - {"cornsilk", 0xFFF8DC}, - {"crimson", 0xDC143C}, - {"cyan", 0x00FFFF}, - {"darkblue", 0x00008B}, - {"darkcyan", 0x008B8B}, - {"darkgoldenrod", 0xB8860B}, - {"darkgray", 0xA9A9A9}, - {"darkgreen", 0x006400}, - {"darkgrey", 0xA9A9A9}, - {"darkkhaki", 0xBDB76B}, - {"darkmagenta", 0x8B008B}, - {"darkolivegreen", 0x556B2F}, - {"darkorange", 0xFF8C00}, - {"darkorchid", 0x9932CC}, - {"darkred", 0x8B0000}, - {"darksalmon", 0xE9967A}, - {"darkseagreen", 0x8FBC8F}, - {"darkslateblue", 0x483D8B}, - {"darkslategray", 0x2F4F4F}, - {"darkslategrey", 0x2F4F4F}, - {"darkturquoise", 0x00CED1}, - {"darkviolet", 0x9400D3}, - {"deeppink", 0xFF1493}, - {"deepskyblue", 0x00BFFF}, - {"dimgray", 0x696969}, - {"dimgrey", 0x696969}, - {"dodgerblue", 0x1E90FF}, - {"firebrick", 0xB22222}, - {"floralwhite", 0xFFFAF0}, - {"forestgreen", 0x228B22}, - {"fuchsia", 0xFF00FF}, - {"gainsboro", 0xDCDCDC}, - {"ghostwhite", 0xF8F8FF}, - {"gold", 0xFFD700}, - {"goldenrod", 0xDAA520}, - {"gray", 0x808080}, - {"green", 0x008000}, - {"greenyellow", 0xADFF2F}, - {"grey", 0x808080}, - {"honeydew", 0xF0FFF0}, - {"hotpink", 0xFF69B4}, - {"indianred", 0xCD5C5C}, - {"indigo", 0x4B0082}, - {"ivory", 0xFFFFF0}, - {"khaki", 0xF0E68C}, - {"lavender", 0xE6E6FA}, - {"lavenderblush", 0xFFF0F5}, - {"lawngreen", 0x7CFC00}, - {"lemonchiffon", 0xFFFACD}, - {"lightblue", 0xADD8E6}, - {"lightcoral", 0xF08080}, - {"lightcyan", 0xE0FFFF}, - {"lightgoldenrodyellow", 0xFAFAD2}, - {"lightgray", 0xD3D3D3}, - {"lightgreen", 0x90EE90}, - {"lightgrey", 0xD3D3D3}, - {"lightpink", 0xFFB6C1}, - {"lightsalmon", 0xFFA07A}, - {"lightseagreen", 0x20B2AA}, - {"lightskyblue", 0x87CEFA}, - {"lightslategray", 0x778899}, - {"lightslategrey", 0x778899}, - {"lightsteelblue", 0xB0C4DE}, - {"lightyellow", 0xFFFFE0}, - {"lime", 0x00FF00}, - {"limegreen", 0x32CD32}, - {"linen", 0xFAF0E6}, - {"magenta", 0xFF00FF}, - {"maroon", 0x800000}, - {"mediumaquamarine", 0x66CDAA}, - {"mediumblue", 0x0000CD}, - {"mediumorchid", 0xBA55D3}, - {"mediumpurple", 0x9370DB}, - {"mediumseagreen", 0x3CB371}, - {"mediumslateblue", 0x7B68EE}, - {"mediumspringgreen", 0x00FA9A}, - {"mediumturquoise", 0x48D1CC}, - {"mediumvioletred", 0xC71585}, - {"midnightblue", 0x191970}, - {"mintcream", 0xF5FFFA}, - {"mistyrose", 0xFFE4E1}, - {"moccasin", 0xFFE4B5}, - {"navajowhite", 0xFFDEAD}, - {"navy", 0x000080}, - {"oldlace", 0xFDF5E6}, - {"olive", 0x808000}, - {"olivedrab", 0x6B8E23}, - {"orange", 0xFFA500}, - {"orangered", 0xFF4500}, - {"orchid", 0xDA70D6}, - {"palegoldenrod", 0xEEE8AA}, - {"palegreen", 0x98FB98}, - {"paleturquoise", 0xAFEEEE}, - {"palevioletred", 0xDB7093}, - {"papayawhip", 0xFFEFD5}, - {"peachpuff", 0xFFDAB9}, - {"peru", 0xCD853F}, - {"pink", 0xFFC0CB}, - {"plum", 0xDDA0DD}, - {"powderblue", 0xB0E0E6}, - {"purple", 0x800080}, - {"rebeccapurple", 0x663399}, - {"red", 0xFF0000}, - {"rosybrown", 0xBC8F8F}, - {"royalblue", 0x4169E1}, - {"saddlebrown", 0x8B4513}, - {"salmon", 0xFA8072}, - {"sandybrown", 0xF4A460}, - {"seagreen", 0x2E8B57}, - {"seashell", 0xFFF5EE}, - {"sienna", 0xA0522D}, - {"silver", 0xC0C0C0}, - {"skyblue", 0x87CEEB}, - {"slateblue", 0x6A5ACD}, - {"slategray", 0x708090}, - {"slategrey", 0x708090}, - {"snow", 0xFFFAFA}, - {"springgreen", 0x00FF7F}, - {"steelblue", 0x4682B4}, - {"tan", 0xD2B48C}, - {"teal", 0x008080}, - {"thistle", 0xD8BFD8}, - {"tomato", 0xFF6347}, - {"turquoise", 0x40E0D0}, - {"violet", 0xEE82EE}, - {"wheat", 0xF5DEB3}, - {"white", 0xFFFFFF}, - {"whitesmoke", 0xF5F5F5}, - {"yellow", 0xFFFF00}, - {"yellowgreen", 0x9ACD32}, -}; - -static int -hexval (char c) -{ - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - return -1; -} - -/* Parse SVG color value; returns HB_COLOR with alpha = 255. - * Sets *is_none if "none". */ -hb_color_t -hb_raster_svg_parse_color (hb_svg_str_t s, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette, - bool *is_none) -{ - *is_none = false; - s = s.trim (); - if (!s.len) { *is_none = true; return HB_COLOR (0, 0, 0, 0); } - - if (s.eq_ascii_ci ("none") || s.eq_ascii_ci ("transparent")) - { - *is_none = true; - return HB_COLOR (0, 0, 0, 0); - } - - if (s.eq_ascii_ci ("currentColor")) - return foreground; - - /* var(--colorN) → CPAL palette color */ - if (s.starts_with_ascii_ci ("var(")) - { - const char *p = s.data + 4; - const char *e = s.data + s.len; - while (p < e && *p == ' ') p++; - if (p + 7 < e && p[0] == '-' && p[1] == '-' && p[2] == 'c' && - p[3] == 'o' && p[4] == 'l' && p[5] == 'o' && p[6] == 'r') - { - p += 7; - unsigned color_index = 0; - while (p < e && *p >= '0' && *p <= '9') - color_index = color_index * 10 + (*p++ - '0'); - - hb_color_t palette_color; - if (hb_paint_custom_palette_color (pfuncs, paint_data, color_index, &palette_color)) - return palette_color; - - unsigned count = 1; - hb_ot_color_palette_get_colors (face, palette, color_index, &count, &palette_color); - if (count) - return palette_color; - } - - /* Fallback value after comma: var(--colorN, fallback) */ - p = s.data + 4; - while (p < e && *p != ',') p++; - if (p < e) - { - p++; - while (p < e && *p == ' ') p++; - const char *val_start = p; - /* Find closing paren */ - while (e > val_start && *(e - 1) != ')') e--; - if (e > val_start) e--; - hb_svg_str_t fallback = {val_start, (unsigned) (e - val_start)}; - return hb_raster_svg_parse_color (fallback, pfuncs, paint_data, foreground, face, palette, is_none); - } - - return foreground; - } - - /* #RGB or #RRGGBB */ - if (s.data[0] == '#') - { - if (s.len == 4) /* #RGB */ - { - int r = hexval (s.data[1]); - int g = hexval (s.data[2]); - int b = hexval (s.data[3]); - if (r < 0 || g < 0 || b < 0) return HB_COLOR (0, 0, 0, 255); - return HB_COLOR (b * 17, g * 17, r * 17, 255); - } - if (s.len == 7) /* #RRGGBB */ - { - int r = hexval (s.data[1]) * 16 + hexval (s.data[2]); - int g = hexval (s.data[3]) * 16 + hexval (s.data[4]); - int b = hexval (s.data[5]) * 16 + hexval (s.data[6]); - return HB_COLOR (b, g, r, 255); - } - return HB_COLOR (0, 0, 0, 255); - } - - /* rgb(r, g, b) or rgb(r%, g%, b%) */ - if (s.starts_with ("rgb")) - { - const char *p = s.data + 3; - const char *e = s.data + s.len; - while (p < e && *p != '(') p++; - if (p < e) p++; - - auto read_component = [&] () -> int { - while (p < e && (*p == ' ' || *p == ',')) p++; - char buf[32]; - unsigned n = 0; - while (p < e && n < sizeof (buf) - 1 && ((*p >= '0' && *p <= '9') || *p == '.' || *p == '-')) - buf[n++] = *p++; - bool is_pct = (p < e && *p == '%'); - if (is_pct) p++; - buf[n] = '\0'; - float val = strtof (buf, nullptr); - if (is_pct) val = val * 255.f / 100.f; - return hb_clamp ((int) (val + 0.5f), 0, 255); - }; - - int r = read_component (); - int g = read_component (); - int b = read_component (); - return HB_COLOR (b, g, r, 255); - } - - /* Named colors (case-insensitive comparison) */ - { - char lower[32]; - unsigned n = hb_min (s.len, (unsigned) sizeof (lower) - 1); - for (unsigned i = 0; i < n; i++) - lower[i] = (s.data[i] >= 'A' && s.data[i] <= 'Z') ? s.data[i] + 32 : s.data[i]; - lower[n] = '\0'; - - for (unsigned i = 0; i < ARRAY_LENGTH (svg_named_colors); i++) - if (strcmp (lower, svg_named_colors[i].name) == 0) - { - uint32_t rgb = svg_named_colors[i].rgb; - return HB_COLOR (rgb & 0xFF, (rgb >> 8) & 0xFF, (rgb >> 16) & 0xFF, 255); - } - } - - return HB_COLOR (0, 0, 0, 255); -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.hh deleted file mode 100644 index 893072e140..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-color.hh +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_COLOR_HH -#define HB_RASTER_SVG_COLOR_HH - -#include "hb.hh" - -#include "hb-face.hh" -#include "hb-raster-svg-base.hh" - -HB_INTERNAL hb_color_t -hb_raster_svg_parse_color (hb_svg_str_t s, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette, - bool *is_none); - -#endif /* HB_RASTER_SVG_COLOR_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-context.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-context.hh deleted file mode 100644 index 5882cab177..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-context.hh +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_CONTEXT_HH -#define HB_RASTER_SVG_CONTEXT_HH - -#include "hb.hh" - -#include "OT/Color/svg/svg.hh" -#include "hb-decycler.hh" -#include "hb-raster-paint.hh" -#include "hb-raster-svg-base.hh" -#include "hb-raster-svg-defs.hh" - -struct hb_svg_fill_context_t -{ - hb_raster_paint_t *paint; - hb_paint_funcs_t *pfuncs; - hb_font_t *font; - unsigned palette; - hb_svg_defs_t *defs; -}; - -struct hb_svg_use_context_t -{ - hb_raster_paint_t *paint; - hb_paint_funcs_t *pfuncs; - - const char *doc_start; - unsigned doc_len; - const OT::SVG::accelerator_t *svg_accel; - const OT::SVG::svg_doc_cache_t *doc_cache; - hb_decycler_t *use_decycler; -}; - -struct hb_svg_render_context_t -{ - hb_raster_paint_t *paint; - hb_paint_funcs_t *pfuncs; - hb_font_t *font; - unsigned palette; - hb_color_t foreground; - hb_svg_defs_t defs; - int depth = 0; - - const char *doc_start; - unsigned doc_len; - const OT::SVG::accelerator_t *svg_accel = nullptr; - const OT::SVG::svg_doc_cache_t *doc_cache = nullptr; - hb_decycler_t use_decycler; - bool suppress_viewbox_once = false; - bool allow_symbol_render_once = false; - - void push_transform (float xx, float yx, float xy, float yy, float dx, float dy) - { - hb_paint_push_transform (pfuncs, paint, xx, yx, xy, yy, dx, dy); - } - void pop_transform () - { - hb_paint_pop_transform (pfuncs, paint); - } - void push_group () - { - hb_paint_push_group (pfuncs, paint); - } - void pop_group (hb_paint_composite_mode_t mode) - { - hb_paint_pop_group (pfuncs, paint, mode); - } - void paint_color (hb_color_t color) - { - hb_paint_color (pfuncs, paint, false, color); - } - void pop_clip () - { - hb_paint_pop_clip (pfuncs, paint); - } -}; - -struct hb_svg_cascade_t -{ - hb_svg_str_t fill; - float fill_opacity = 1.f; - hb_svg_str_t clip_path; - hb_color_t color = HB_COLOR (0, 0, 0, 255); - bool visibility = true; - float opacity = 1.f; -}; - -#endif /* HB_RASTER_SVG_CONTEXT_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.cc deleted file mode 100644 index 3b90b457eb..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-defs-scan.hh" - -#include "hb-raster-svg-clip.hh" -#include "hb-raster-svg-gradient.hh" - -static inline bool -hb_raster_svg_process_defs_child_tag (const hb_svg_defs_scan_context_t *ctx, - hb_svg_xml_parser_t &parser, - hb_svg_token_type_t tok) -{ - if (parser.tag_name.eq ("linearGradient")) - { - hb_raster_svg_process_gradient_def (ctx->defs, parser, tok, SVG_GRADIENT_LINEAR, - ctx->pfuncs, ctx->paint_data, - ctx->foreground, ctx->face, - ctx->palette); - return true; - } - if (parser.tag_name.eq ("radialGradient")) - { - hb_raster_svg_process_gradient_def (ctx->defs, parser, tok, SVG_GRADIENT_RADIAL, - ctx->pfuncs, ctx->paint_data, - ctx->foreground, ctx->face, - ctx->palette); - return true; - } - if (parser.tag_name.eq ("clipPath")) - { - hb_raster_svg_process_clip_path_def (ctx->defs, parser, tok, - ctx->doc_start, ctx->doc_len, - ctx->svg_accel, ctx->doc_cache); - return true; - } - return false; -} - -void -hb_raster_svg_process_defs_element (const hb_svg_defs_scan_context_t *ctx, - hb_svg_xml_parser_t &parser) -{ - int depth = 1; - - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - - if (tok == SVG_TOKEN_CLOSE_TAG) - { - depth--; - continue; - } - - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - { - if (!hb_raster_svg_process_defs_child_tag (ctx, parser, tok) && - tok == SVG_TOKEN_OPEN_TAG) - depth++; - } - } -} - -void -hb_raster_svg_collect_defs (const hb_svg_defs_scan_context_t *ctx, - const char *data, - unsigned data_len) -{ - hb_svg_xml_parser_t parser (data, data_len); - while (true) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - hb_raster_svg_process_defs_child_tag (ctx, parser, tok); - } -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.hh deleted file mode 100644 index bddad1f74c..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs-scan.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_DEFS_SCAN_HH -#define HB_RASTER_SVG_DEFS_SCAN_HH - -#include "hb.hh" - -#include "OT/Color/svg/svg.hh" -#include "hb-raster-svg-defs.hh" - -struct hb_svg_defs_scan_context_t -{ - hb_svg_defs_t *defs; - hb_paint_funcs_t *pfuncs; - void *paint_data; - hb_color_t foreground; - hb_face_t *face; - unsigned palette; - const char *doc_start; - unsigned doc_len; - const OT::SVG::accelerator_t *svg_accel; - const OT::SVG::svg_doc_cache_t *doc_cache; -}; - -HB_INTERNAL void -hb_raster_svg_process_defs_element (const hb_svg_defs_scan_context_t *ctx, - hb_svg_xml_parser_t &parser); - -HB_INTERNAL void -hb_raster_svg_collect_defs (const hb_svg_defs_scan_context_t *ctx, - const char *data, - unsigned data_len); - -#endif /* HB_RASTER_SVG_DEFS_SCAN_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.cc deleted file mode 100644 index ee6787d375..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-defs.hh" - -#include - -hb_svg_defs_t::~hb_svg_defs_t () -{ - for (unsigned i = 0; i < owned_id_strings.length; i++) - hb_free (owned_id_strings.arrayZ[i]); -} - -bool -hb_svg_defs_t::add_id_mapping (hb_hashmap_t *map, - hb_bytes_t id, - unsigned idx) -{ - if (!id.length) - return false; - if (map->has (id)) - return true; - - unsigned n = (unsigned) id.length; - char *owned = (char *) hb_malloc (n + 1); - if (unlikely (!owned)) - return false; - hb_memcpy (owned, id.arrayZ, n); - owned[n] = '\0'; - if (unlikely (!owned_id_strings.push (owned))) - { - hb_free (owned); - return false; - } - - hb_bytes_t owned_key = hb_bytes_t (owned, n); - if (unlikely (!map->set (owned_key, idx))) - return false; - return true; -} - -bool -hb_svg_defs_t::add_gradient (hb_bytes_t id, const hb_svg_gradient_t &grad) -{ - unsigned idx = gradients.length; - gradients.push (grad); - if (unlikely (gradients.in_error ())) - return false; - - if (unlikely (!add_id_mapping (&gradient_by_id, id, idx))) - { - gradients.pop (); - return false; - } - return true; -} - -const hb_svg_gradient_t * -hb_svg_defs_t::find_gradient (hb_bytes_t id) const -{ - if (!id.length) return nullptr; - unsigned *idx = nullptr; - if (gradient_by_id.has (id, &idx)) - return &gradients[*idx]; - return nullptr; -} - -bool -hb_svg_defs_t::add_clip_path (hb_bytes_t id, const hb_svg_clip_path_def_t &clip) -{ - unsigned idx = clip_paths.length; - clip_paths.push (clip); - if (unlikely (clip_paths.in_error ())) - return false; - - if (unlikely (!add_id_mapping (&clip_path_by_id, id, idx))) - { - clip_paths.pop (); - return false; - } - return true; -} - -const hb_svg_clip_path_def_t * -hb_svg_defs_t::find_clip_path (hb_bytes_t id) const -{ - if (!id.length) return nullptr; - unsigned *idx = nullptr; - if (clip_path_by_id.has (id, &idx)) - return &clip_paths[*idx]; - return nullptr; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.hh deleted file mode 100644 index ca1855658b..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-defs.hh +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_DEFS_HH -#define HB_RASTER_SVG_DEFS_HH - -#include "hb.hh" - -#include "hb-map.hh" -#include "hb-raster-svg-parse.hh" - -enum hb_svg_gradient_type_t -{ - SVG_GRADIENT_LINEAR, - SVG_GRADIENT_RADIAL -}; - -struct hb_svg_gradient_stop_t -{ - float offset; - hb_color_t color; - bool is_current_color = false; -}; - -struct hb_svg_gradient_t -{ - hb_svg_gradient_type_t type; - - hb_paint_extend_t spread = HB_PAINT_EXTEND_PAD; - bool has_spread = false; - hb_svg_transform_t gradient_transform; - bool has_gradient_transform = false; - bool units_user_space = false; - bool has_units_user_space = false; - - float x1 = 0, y1 = 0, x2 = 1, y2 = 0; - bool has_x1 = false, has_y1 = false, has_x2 = false, has_y2 = false; - - float cx = 0.5f, cy = 0.5f, r = 0.5f; - float fx = -1.f, fy = -1.f, fr = 0.f; - bool has_cx = false, has_cy = false, has_r = false; - bool has_fx = false, has_fy = false, has_fr = false; - - hb_vector_t stops; - - hb_bytes_t href_id = {}; -}; - -struct hb_svg_clip_path_def_t -{ - unsigned first_shape = 0; - unsigned shape_count = 0; - hb_svg_transform_t clip_transform; - bool has_clip_transform = false; - bool units_user_space = true; -}; - -struct hb_svg_clip_shape_t -{ - hb_svg_shape_emit_data_t shape; - hb_svg_transform_t transform; - bool has_transform = false; -}; - -struct hb_svg_defs_t -{ - hb_vector_t gradients; - hb_vector_t clip_shapes; - hb_vector_t clip_paths; - hb_hashmap_t gradient_by_id; - hb_hashmap_t clip_path_by_id; - hb_vector_t owned_id_strings; - - ~hb_svg_defs_t (); - - bool add_id_mapping (hb_hashmap_t *map, - hb_bytes_t id, - unsigned idx); - bool add_gradient (hb_bytes_t id, const hb_svg_gradient_t &grad); - const hb_svg_gradient_t *find_gradient (hb_bytes_t id) const; - bool add_clip_path (hb_bytes_t id, const hb_svg_clip_path_def_t &clip); - const hb_svg_clip_path_def_t *find_clip_path (hb_bytes_t id) const; -}; - -#endif /* HB_RASTER_SVG_DEFS_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.cc deleted file mode 100644 index 2667cbd910..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.cc +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-fill.hh" - -#include "hb-raster-svg-base.hh" -#include "hb-raster-svg-color.hh" -#include "hb-decycler.hh" - -#include - -struct hb_svg_color_line_data_t -{ - const hb_svg_gradient_t *grad; - hb_paint_extend_t extend; - float alpha_scale; - hb_color_t current_color; -}; - -static unsigned -svg_color_line_get_stops (hb_color_line_t *color_line HB_UNUSED, - void *color_line_data, - unsigned int start, - unsigned int *count, - hb_color_stop_t *color_stops, - void *user_data HB_UNUSED) -{ - hb_svg_color_line_data_t *cl = (hb_svg_color_line_data_t *) color_line_data; - const hb_svg_gradient_t *grad = cl->grad; - unsigned total = grad->stops.length; - - if (count) - { - unsigned n = hb_min (*count, total > start ? total - start : 0u); - for (unsigned i = 0; i < n; i++) - { - const hb_svg_gradient_stop_t &stop = grad->stops[start + i]; - color_stops[i].offset = stop.offset; - color_stops[i].is_foreground = false; - hb_color_t c = stop.is_current_color ? cl->current_color : stop.color; - if (stop.is_current_color) - { - uint8_t a = (uint8_t) hb_raster_div255 (hb_color_get_alpha (c) * hb_color_get_alpha (stop.color)); - c = HB_COLOR (hb_color_get_blue (c), - hb_color_get_green (c), - hb_color_get_red (c), - a); - } - if (cl->alpha_scale < 1.f) - { - uint8_t a = (uint8_t) hb_clamp ((int) (hb_color_get_alpha (c) * cl->alpha_scale + 0.5f), 0, 255); - c = HB_COLOR (hb_color_get_blue (c), - hb_color_get_green (c), - hb_color_get_red (c), - a); - } - color_stops[i].color = c; - } - *count = n; - } - return total; -} - -static hb_paint_extend_t -svg_color_line_get_extend (hb_color_line_t *color_line HB_UNUSED, - void *color_line_data, - void *user_data HB_UNUSED) -{ - hb_svg_color_line_data_t *cl = (hb_svg_color_line_data_t *) color_line_data; - return cl->extend; -} - -static bool -svg_parse_paint_url_with_fallback (hb_svg_str_t s, - hb_svg_str_t *out_id, - hb_svg_str_t *fallback) -{ - if (out_id) *out_id = {}; - hb_svg_str_t id; - if (!hb_raster_svg_parse_local_id_ref (s, &id, fallback)) - return false; - if (!s.trim ().starts_with_ascii_ci ("url(")) - return false; - if (out_id) *out_id = id; - return id.len > 0; -} - -void -hb_raster_svg_emit_fill (const hb_svg_fill_context_t *ctx, - hb_svg_str_t fill_str, - float fill_opacity, - const hb_extents_t<> *object_bbox, - hb_color_t current_color) -{ - bool is_none = false; - - hb_svg_str_t url_id; - hb_svg_str_t fallback_paint; - bool has_url_paint = svg_parse_paint_url_with_fallback (fill_str, &url_id, &fallback_paint); - - const hb_svg_gradient_t *grad = has_url_paint ? ctx->defs->find_gradient (hb_bytes_t (url_id.data, url_id.len)) : nullptr; - if (has_url_paint && !grad) - { - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - if (grad) - { - const unsigned SVG_MAX_GRADIENT_REF_DEPTH = 1024; - hb_vector_t chain; - hb_decycler_t decycler; - const hb_svg_gradient_t *cur = grad; - while (cur) - { - if (chain.length >= SVG_MAX_GRADIENT_REF_DEPTH) - break; - - hb_decycler_node_t node (decycler); - if (unlikely (!node.visit ((uintptr_t) cur))) - break; - - chain.push (cur); - if (unlikely (chain.in_error ())) - { - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - - if (!cur->href_id.length) break; - const hb_svg_gradient_t *next = ctx->defs->find_gradient (cur->href_id); - if (!next) break; - cur = next; - } - if (!chain.length) - { - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - - if (!chain.length) { - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - hb_svg_gradient_t effective = *chain.arrayZ[chain.length - 1]; - for (int i = (int) chain.length - 2; i >= 0; i--) - { - const hb_svg_gradient_t *g = chain.arrayZ[i]; - effective.type = g->type; - if (g->stops.length) effective.stops = g->stops; - if (g->has_spread) { effective.spread = g->spread; effective.has_spread = true; } - if (g->has_units_user_space) - { - effective.units_user_space = g->units_user_space; - effective.has_units_user_space = true; - } - if (g->has_gradient_transform) - { - effective.gradient_transform = g->gradient_transform; - effective.has_gradient_transform = true; - } - if (g->has_x1) { effective.x1 = g->x1; effective.has_x1 = true; } - if (g->has_y1) { effective.y1 = g->y1; effective.has_y1 = true; } - if (g->has_x2) { effective.x2 = g->x2; effective.has_x2 = true; } - if (g->has_y2) { effective.y2 = g->y2; effective.has_y2 = true; } - if (g->has_cx) { effective.cx = g->cx; effective.has_cx = true; } - if (g->has_cy) { effective.cy = g->cy; effective.has_cy = true; } - if (g->has_r) { effective.r = g->r; effective.has_r = true; } - if (g->has_fx) { effective.fx = g->fx; effective.has_fx = true; } - if (g->has_fy) { effective.fy = g->fy; effective.has_fy = true; } - if (g->has_fr) { effective.fr = g->fr; effective.has_fr = true; } - } - if (!effective.stops.length) - { - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - - hb_svg_color_line_data_t cl_data; - cl_data.grad = &effective; - cl_data.extend = effective.spread; - cl_data.alpha_scale = hb_clamp (fill_opacity, 0.f, 1.f); - cl_data.current_color = current_color; - - hb_color_line_t cl = { - &cl_data, - svg_color_line_get_stops, nullptr, - svg_color_line_get_extend, nullptr - }; - - bool has_bbox_transform = !effective.units_user_space && object_bbox && !object_bbox->is_empty (); - if (has_bbox_transform) - { - float w = object_bbox->xmax - object_bbox->xmin; - float h = object_bbox->ymax - object_bbox->ymin; - if (isfinite (w) && isfinite (h) && w > 0.f && h > 0.f) - hb_paint_push_transform (ctx->pfuncs, ctx->paint, w, 0, 0, h, object_bbox->xmin, object_bbox->ymin); - else - has_bbox_transform = false; - } - - if (effective.has_gradient_transform) - hb_paint_push_transform (ctx->pfuncs, ctx->paint, - effective.gradient_transform.xx, - effective.gradient_transform.yx, - effective.gradient_transform.xy, - effective.gradient_transform.yy, - effective.gradient_transform.dx, - effective.gradient_transform.dy); - - if (effective.type == SVG_GRADIENT_LINEAR) - { - hb_paint_linear_gradient (ctx->pfuncs, ctx->paint, &cl, - effective.x1, effective.y1, - effective.x2, effective.y2, - effective.x2 - (effective.y2 - effective.y1), - effective.y2 + (effective.x2 - effective.x1)); - } - else - { - if (!isfinite (effective.r) || effective.r < 0.f) - { - if (effective.has_gradient_transform) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - if (has_bbox_transform) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - if (fallback_paint.len) - hb_raster_svg_emit_fill (ctx, fallback_paint, fill_opacity, object_bbox, current_color); - return; - } - - float fx = effective.has_fx ? effective.fx : effective.cx; - float fy = effective.has_fy ? effective.fy : effective.cy; - float fr = effective.has_fr ? effective.fr : 0.f; - if (!isfinite (fr) || fr < 0.f) - fr = 0.f; - fr = hb_min (fr, effective.r); - - hb_paint_radial_gradient (ctx->pfuncs, ctx->paint, &cl, - fx, fy, fr, - effective.cx, effective.cy, effective.r); - } - - if (effective.has_gradient_transform) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - if (has_bbox_transform) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - - return; - } - - hb_color_t color = hb_raster_svg_parse_color (fill_str, - ctx->pfuncs, - ctx->paint, - current_color, - hb_font_get_face (ctx->font), - ctx->palette, - &is_none); - if (is_none) return; - - if (fill_opacity < 1.f) - color = HB_COLOR (hb_color_get_blue (color), - hb_color_get_green (color), - hb_color_get_red (color), - (uint8_t) (hb_color_get_alpha (color) * fill_opacity + 0.5f)); - - hb_paint_color (ctx->pfuncs, ctx->paint, false, color); -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.hh deleted file mode 100644 index ce4ceecd91..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-fill.hh +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_FILL_HH -#define HB_RASTER_SVG_FILL_HH - -#include "hb.hh" - -#include "hb-raster-svg-context.hh" - -HB_INTERNAL void -hb_raster_svg_emit_fill (const hb_svg_fill_context_t *ctx, - hb_svg_str_t fill_str, - float fill_opacity, - const hb_extents_t<> *object_bbox, - hb_color_t current_color); - -#endif /* HB_RASTER_SVG_FILL_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.cc deleted file mode 100644 index 36e5be8dc7..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.cc +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-gradient.hh" - -#include "hb-raster-svg-base.hh" - -static bool -svg_parse_gradient_stop (hb_svg_xml_parser_t &parser, - hb_svg_gradient_t &grad, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette) -{ - const unsigned SVG_MAX_GRADIENT_STOPS = 1024; - if (grad.stops.length >= SVG_MAX_GRADIENT_STOPS) - return true; - - hb_svg_attr_view_t attrs (parser); - hb_svg_str_t style = attrs.get ("style"); - hb_svg_style_props_t style_props; - svg_parse_style_props (style, &style_props); - hb_svg_str_t offset_str = svg_pick_attr_or_style (parser, style_props.offset, "offset"); - hb_svg_str_t color_str = svg_pick_attr_or_style (parser, style_props.stop_color, "stop-color"); - hb_svg_str_t opacity_str = svg_pick_attr_or_style (parser, style_props.stop_opacity, "stop-opacity"); - hb_svg_str_t display_str = svg_pick_attr_or_style (parser, style_props.display, "display"); - hb_svg_str_t visibility_str = svg_pick_attr_or_style (parser, style_props.visibility, "visibility"); - - if (display_str.trim ().eq_ascii_ci ("none")) - return true; - hb_svg_str_t visibility_trim = visibility_str.trim (); - if (visibility_trim.eq_ascii_ci ("hidden") || - visibility_trim.eq_ascii_ci ("collapse")) - return true; - - float offset = 0; - if (offset_str.len) - offset = hb_clamp (svg_parse_number_or_percent (offset_str, nullptr), 0.f, 1.f); - if (grad.stops.length) - offset = hb_max (offset, grad.stops.arrayZ[grad.stops.length - 1].offset); - - bool is_none = false; - hb_color_t color = HB_COLOR (0, 0, 0, 255); - bool is_current_color = false; - if (color_str.len && !svg_str_is_inherit (color_str)) - { - is_current_color = color_str.trim ().eq_ascii_ci ("currentColor"); - color = hb_raster_svg_parse_color (color_str, pfuncs, paint_data, foreground, face, palette, &is_none); - } - - if (opacity_str.len && !svg_str_is_inherit (opacity_str)) - { - float opacity = svg_parse_float_clamped01 (opacity_str); - color = HB_COLOR (hb_color_get_blue (color), - hb_color_get_green (color), - hb_color_get_red (color), - (uint8_t) (hb_color_get_alpha (color) * opacity + 0.5f)); - } - - hb_svg_gradient_stop_t stop; - stop.offset = offset; - stop.color = color; - stop.is_current_color = is_current_color; - grad.stops.push (stop); - return !grad.stops.in_error (); -} - -static void -svg_parse_gradient_attrs (hb_svg_xml_parser_t &parser, - hb_svg_gradient_t &grad) -{ - hb_svg_style_props_t style_props; - svg_parse_style_props (parser.find_attr ("style"), &style_props); - - hb_svg_str_t spread_str = svg_pick_attr_or_style (parser, style_props.spread_method, "spreadMethod").trim (); - if (spread_str.eq_ascii_ci ("reflect")) - { - grad.spread = HB_PAINT_EXTEND_REFLECT; - grad.has_spread = true; - } - else if (spread_str.eq_ascii_ci ("repeat")) - { - grad.spread = HB_PAINT_EXTEND_REPEAT; - grad.has_spread = true; - } - else if (spread_str.eq_ascii_ci ("pad")) - { - grad.spread = HB_PAINT_EXTEND_PAD; - grad.has_spread = true; - } - - hb_svg_str_t units_str = svg_pick_attr_or_style (parser, style_props.gradient_units, "gradientUnits").trim (); - if (units_str.eq_ascii_ci ("userSpaceOnUse")) - { - grad.units_user_space = true; - grad.has_units_user_space = true; - } - else if (units_str.eq_ascii_ci ("objectBoundingBox")) - { - grad.units_user_space = false; - grad.has_units_user_space = true; - } - - hb_svg_str_t transform_str = svg_pick_attr_or_style (parser, style_props.gradient_transform, "gradientTransform"); - if (transform_str.len) - { - grad.has_gradient_transform = true; - hb_raster_svg_parse_transform (transform_str, &grad.gradient_transform); - } - - hb_svg_str_t href = hb_raster_svg_find_href_attr (parser); - if (href.len) - { - hb_svg_str_t href_id; - if (hb_raster_svg_parse_local_id_ref (href, &href_id, nullptr)) - grad.href_id = hb_bytes_t (href_id.data, href_id.len); - } -} - -static void -svg_parse_gradient_geometry_attrs (hb_svg_xml_parser_t &parser, - hb_svg_gradient_t &grad) -{ - hb_svg_style_props_t style_props; - svg_parse_style_props (parser.find_attr ("style"), &style_props); - if (grad.type == SVG_GRADIENT_LINEAR) - { - hb_svg_str_t x1_str = svg_pick_attr_or_style (parser, style_props.x1, "x1"); - hb_svg_str_t y1_str = svg_pick_attr_or_style (parser, style_props.y1, "y1"); - hb_svg_str_t x2_str = svg_pick_attr_or_style (parser, style_props.x2, "x2"); - hb_svg_str_t y2_str = svg_pick_attr_or_style (parser, style_props.y2, "y2"); - if (x1_str.len) { grad.x1 = svg_parse_number_or_percent (x1_str, nullptr); grad.has_x1 = true; } - if (y1_str.len) { grad.y1 = svg_parse_number_or_percent (y1_str, nullptr); grad.has_y1 = true; } - if (x2_str.len) { grad.x2 = svg_parse_number_or_percent (x2_str, nullptr); grad.has_x2 = true; } - if (y2_str.len) { grad.y2 = svg_parse_number_or_percent (y2_str, nullptr); grad.has_y2 = true; } - - if (!grad.has_x2) - grad.x2 = 1.f; - } - else - { - hb_svg_str_t cx_str = svg_pick_attr_or_style (parser, style_props.cx, "cx"); - hb_svg_str_t cy_str = svg_pick_attr_or_style (parser, style_props.cy, "cy"); - hb_svg_str_t r_str = svg_pick_attr_or_style (parser, style_props.r, "r"); - hb_svg_str_t fx_str = svg_pick_attr_or_style (parser, style_props.fx, "fx"); - hb_svg_str_t fy_str = svg_pick_attr_or_style (parser, style_props.fy, "fy"); - hb_svg_str_t fr_str = svg_pick_attr_or_style (parser, style_props.fr, "fr"); - - if (cx_str.len) { grad.cx = svg_parse_number_or_percent (cx_str, nullptr); grad.has_cx = true; } - if (cy_str.len) { grad.cy = svg_parse_number_or_percent (cy_str, nullptr); grad.has_cy = true; } - if (r_str.len) { grad.r = svg_parse_number_or_percent (r_str, nullptr); grad.has_r = true; } - if (fx_str.len) { grad.fx = svg_parse_number_or_percent (fx_str, nullptr); grad.has_fx = true; } - if (fy_str.len) { grad.fy = svg_parse_number_or_percent (fy_str, nullptr); grad.has_fy = true; } - if (fr_str.len) { grad.fr = svg_parse_number_or_percent (fr_str, nullptr); grad.has_fr = true; } - } -} - -static void -svg_parse_gradient_children (hb_svg_defs_t *defs, - hb_svg_xml_parser_t &parser, - hb_svg_gradient_t &grad, - hb_svg_str_t *id, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette) -{ - int gdepth = 1; - bool had_alloc_failure = false; - while (gdepth > 0) - { - hb_svg_token_type_t gt = parser.next (); - if (gt == SVG_TOKEN_EOF) break; - if (gt == SVG_TOKEN_CLOSE_TAG) { gdepth--; continue; } - if ((gt == SVG_TOKEN_OPEN_TAG || gt == SVG_TOKEN_SELF_CLOSE_TAG) && - parser.tag_name.eq ("stop")) - if (unlikely (!svg_parse_gradient_stop (parser, grad, - pfuncs, paint_data, - foreground, face, - palette))) - had_alloc_failure = true; - if (gt == SVG_TOKEN_OPEN_TAG && !parser.tag_name.eq ("stop")) - gdepth++; - } - if (had_alloc_failure || defs->gradients.in_error ()) - *id = {}; -} - -void -hb_raster_svg_process_gradient_def (hb_svg_defs_t *defs, - hb_svg_xml_parser_t &parser, - hb_svg_token_type_t tok, - hb_svg_gradient_type_t type, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette) -{ - hb_svg_gradient_t grad; - grad.type = type; - svg_parse_gradient_geometry_attrs (parser, grad); - svg_parse_gradient_attrs (parser, grad); - - hb_svg_str_t id = parser.find_attr ("id"); - if (tok == SVG_TOKEN_OPEN_TAG) - svg_parse_gradient_children (defs, parser, grad, &id, - pfuncs, paint_data, - foreground, face, - palette); - - if (id.len) - (void) defs->add_gradient (hb_bytes_t (id.data, id.len), grad); -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.hh deleted file mode 100644 index 0b1e6fd0c4..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-gradient.hh +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_GRADIENT_HH -#define HB_RASTER_SVG_GRADIENT_HH - -#include "hb.hh" - -#include "hb-raster-svg-color.hh" -#include "hb-raster-svg-defs.hh" - -HB_INTERNAL void -hb_raster_svg_process_gradient_def (hb_svg_defs_t *defs, - hb_svg_xml_parser_t &parser, - hb_svg_token_type_t tok, - hb_svg_gradient_type_t type, - hb_paint_funcs_t *pfuncs, - void *paint_data, - hb_color_t foreground, - hb_face_t *face, - unsigned palette); - -#endif /* HB_RASTER_SVG_GRADIENT_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.cc deleted file mode 100644 index fcc3c4808e..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.cc +++ /dev/null @@ -1,665 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-parse.hh" - -#include -bool -hb_raster_svg_parse_transform (hb_svg_str_t s, hb_svg_transform_t *out) -{ - hb_svg_float_parser_t fp (s); - - while (fp.p < fp.end) - { - fp.skip_ws_comma (); - if (fp.p >= fp.end) break; - - const char *start = fp.p; - while (fp.p < fp.end && *fp.p != '(') fp.p++; - hb_svg_str_t func_name = {start, (unsigned) (fp.p - start)}; - - while (func_name.len && (func_name.data[func_name.len - 1] == ' ' || - func_name.data[func_name.len - 1] == '\t')) - func_name.len--; - - if (fp.p >= fp.end) break; - fp.p++; - - hb_svg_transform_t t; - - if (func_name.eq_ascii_ci ("matrix")) - { - t.xx = fp.next_float (); - t.yx = fp.next_float (); - t.xy = fp.next_float (); - t.yy = fp.next_float (); - t.dx = fp.next_float (); - t.dy = fp.next_float (); - } - else if (func_name.eq_ascii_ci ("translate")) - { - t.dx = fp.next_float (); - fp.skip_ws_comma (); - if (fp.p < fp.end && *fp.p != ')') - t.dy = fp.next_float (); - } - else if (func_name.eq_ascii_ci ("scale")) - { - t.xx = fp.next_float (); - fp.skip_ws_comma (); - if (fp.p < fp.end && *fp.p != ')') - t.yy = fp.next_float (); - else - t.yy = t.xx; - } - else if (func_name.eq_ascii_ci ("rotate")) - { - float angle = fp.next_float () * (float) M_PI / 180.f; - float cs = cosf (angle), sn = sinf (angle); - fp.skip_ws_comma (); - if (fp.p < fp.end && *fp.p != ')') - { - float cx = fp.next_float (); - float cy = fp.next_float (); - t.xx = cs; t.yx = sn; - t.xy = -sn; t.yy = cs; - t.dx = cx - cs * cx + sn * cy; - t.dy = cy - sn * cx - cs * cy; - } - else - { - t.xx = cs; t.yx = sn; - t.xy = -sn; t.yy = cs; - } - } - else if (func_name.eq_ascii_ci ("skewX")) - { - float angle = fp.next_float () * (float) M_PI / 180.f; - t.xy = tanf (angle); - } - else if (func_name.eq_ascii_ci ("skewY")) - { - float angle = fp.next_float () * (float) M_PI / 180.f; - t.yx = tanf (angle); - } - - while (fp.p < fp.end && *fp.p != ')') fp.p++; - if (fp.p < fp.end) fp.p++; - - out->multiply (t); - } - return true; -} - -static void -svg_arc_to_cubics (hb_draw_funcs_t *dfuncs, void *draw_data, hb_draw_state_t *st, - float cx, float cy, - float rx, float ry, - float phi, float theta1, float dtheta) -{ - int n_segs = (int) ceilf (fabsf (dtheta) / ((float) M_PI / 2.f)); - if (n_segs < 1) n_segs = 1; - float seg_angle = dtheta / n_segs; - - float cos_phi = cosf (phi); - float sin_phi = sinf (phi); - - for (int i = 0; i < n_segs; i++) - { - float t1 = theta1 + i * seg_angle; - float t2 = t1 + seg_angle; - float alpha = sinf (seg_angle) * - (sqrtf (4.f + 3.f * tanf (seg_angle / 2.f) * tanf (seg_angle / 2.f)) - 1.f) / 3.f; - - float cos_t1 = cosf (t1), sin_t1 = sinf (t1); - float cos_t2 = cosf (t2), sin_t2 = sinf (t2); - - float e1x = rx * cos_t1, e1y = ry * sin_t1; - float e2x = rx * cos_t2, e2y = ry * sin_t2; - float d1x = -rx * sin_t1, d1y = ry * cos_t1; - float d2x = -rx * sin_t2, d2y = ry * cos_t2; - - float cp1x = e1x + alpha * d1x; - float cp1y = e1y + alpha * d1y; - float cp2x = e2x - alpha * d2x; - float cp2y = e2y - alpha * d2y; - - float r_cp1x = cos_phi * cp1x - sin_phi * cp1y + cx; - float r_cp1y = sin_phi * cp1x + cos_phi * cp1y + cy; - float r_cp2x = cos_phi * cp2x - sin_phi * cp2y + cx; - float r_cp2y = sin_phi * cp2x + cos_phi * cp2y + cy; - float r_e2x = cos_phi * e2x - sin_phi * e2y + cx; - float r_e2y = sin_phi * e2x + cos_phi * e2y + cy; - - hb_draw_cubic_to (dfuncs, draw_data, st, - r_cp1x, r_cp1y, - r_cp2x, r_cp2y, - r_e2x, r_e2y); - } -} - -static void -svg_arc_endpoint_to_center (float x1, float y1, float x2, float y2, - float rx, float ry, float phi_deg, - bool large_arc, bool sweep, - float *cx_out, float *cy_out, - float *theta1_out, float *dtheta_out, - float *rx_out, float *ry_out) -{ - float phi = phi_deg * (float) M_PI / 180.f; - float cos_phi = cosf (phi), sin_phi = sinf (phi); - - float mx = (x1 - x2) / 2.f; - float my = (y1 - y2) / 2.f; - float x1p = cos_phi * mx + sin_phi * my; - float y1p = -sin_phi * mx + cos_phi * my; - - rx = fabsf (rx); ry = fabsf (ry); - if (rx < 1e-10f || ry < 1e-10f) - { - *cx_out = (x1 + x2) / 2.f; - *cy_out = (y1 + y2) / 2.f; - *theta1_out = 0; - *dtheta_out = 0; - *rx_out = rx; *ry_out = ry; - return; - } - - float x1p2 = x1p * x1p, y1p2 = y1p * y1p; - float rx2 = rx * rx, ry2 = ry * ry; - float lambda = x1p2 / rx2 + y1p2 / ry2; - if (lambda > 1.f) - { - float sl = sqrtf (lambda); - rx *= sl; ry *= sl; - rx2 = rx * rx; ry2 = ry * ry; - } - - float num = rx2 * ry2 - rx2 * y1p2 - ry2 * x1p2; - float den = rx2 * y1p2 + ry2 * x1p2; - float sq = (den > 0.f) ? sqrtf (hb_max (num / den, 0.f)) : 0.f; - if (large_arc == sweep) sq = -sq; - - float cxp = sq * rx * y1p / ry; - float cyp = -sq * ry * x1p / rx; - - float cx = cos_phi * cxp - sin_phi * cyp + (x1 + x2) / 2.f; - float cy = sin_phi * cxp + cos_phi * cyp + (y1 + y2) / 2.f; - - auto angle = [] (float ux, float uy, float vx, float vy) -> float { - float dot = ux * vx + uy * vy; - float len = sqrtf ((ux * ux + uy * uy) * (vx * vx + vy * vy)); - if (!(len > 0.f) || !isfinite (len)) - return 0.f; - float a = acosf (hb_clamp (dot / len, -1.f, 1.f)); - if (ux * vy - uy * vx < 0.f) a = -a; - return a; - }; - - float theta1 = angle (1.f, 0.f, (x1p - cxp) / rx, (y1p - cyp) / ry); - float dtheta = angle ((x1p - cxp) / rx, (y1p - cyp) / ry, - (-x1p - cxp) / rx, (-y1p - cyp) / ry); - - if (!sweep && dtheta > 0.f) dtheta -= 2.f * (float) M_PI; - if (sweep && dtheta < 0.f) dtheta += 2.f * (float) M_PI; - - *cx_out = cx; *cy_out = cy; - *theta1_out = theta1; *dtheta_out = dtheta; - *rx_out = rx; *ry_out = ry; -} - -void -hb_raster_svg_parse_path_data (hb_svg_str_t d, hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - hb_svg_float_parser_t fp (d); - - float cur_x = 0, cur_y = 0; - float start_x = 0, start_y = 0; - float last_cx = 0, last_cy = 0; - char last_cmd = 0; - char cmd = 0; - - while (fp.p < fp.end) - { - fp.skip_ws_comma (); - if (fp.p >= fp.end) break; - - char c = *fp.p; - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) - { - cmd = c; - fp.p++; - } - - switch (cmd) - { - case 'M': case 'm': - { - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 'm') { x += cur_x; y += cur_y; } - hb_draw_move_to (dfuncs, draw_data, &st, x, y); - cur_x = start_x = x; - cur_y = start_y = y; - cmd = (cmd == 'M') ? 'L' : 'l'; - last_cmd = 'M'; - continue; - } - case 'L': case 'l': - { - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 'l') { x += cur_x; y += cur_y; } - hb_draw_line_to (dfuncs, draw_data, &st, x, y); - cur_x = x; cur_y = y; - break; - } - case 'H': case 'h': - { - float x = fp.next_float (); - if (cmd == 'h') x += cur_x; - hb_draw_line_to (dfuncs, draw_data, &st, x, cur_y); - cur_x = x; - break; - } - case 'V': case 'v': - { - float y = fp.next_float (); - if (cmd == 'v') y += cur_y; - hb_draw_line_to (dfuncs, draw_data, &st, cur_x, y); - cur_y = y; - break; - } - case 'C': case 'c': - { - float x1 = fp.next_float (); - float y1 = fp.next_float (); - float x2 = fp.next_float (); - float y2 = fp.next_float (); - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 'c') - { x1 += cur_x; y1 += cur_y; x2 += cur_x; y2 += cur_y; x += cur_x; y += cur_y; } - hb_draw_cubic_to (dfuncs, draw_data, &st, x1, y1, x2, y2, x, y); - last_cx = x2; last_cy = y2; - cur_x = x; cur_y = y; - break; - } - case 'S': case 's': - { - float cx1, cy1; - if (last_cmd == 'C' || last_cmd == 'c' || last_cmd == 'S' || last_cmd == 's') - { cx1 = 2 * cur_x - last_cx; cy1 = 2 * cur_y - last_cy; } - else - { cx1 = cur_x; cy1 = cur_y; } - float x2 = fp.next_float (); - float y2 = fp.next_float (); - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 's') - { x2 += cur_x; y2 += cur_y; x += cur_x; y += cur_y; } - hb_draw_cubic_to (dfuncs, draw_data, &st, cx1, cy1, x2, y2, x, y); - last_cx = x2; last_cy = y2; - cur_x = x; cur_y = y; - break; - } - case 'Q': case 'q': - { - float x1 = fp.next_float (); - float y1 = fp.next_float (); - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 'q') - { x1 += cur_x; y1 += cur_y; x += cur_x; y += cur_y; } - hb_draw_quadratic_to (dfuncs, draw_data, &st, x1, y1, x, y); - last_cx = x1; last_cy = y1; - cur_x = x; cur_y = y; - break; - } - case 'T': case 't': - { - float cx1, cy1; - if (last_cmd == 'Q' || last_cmd == 'q' || last_cmd == 'T' || last_cmd == 't') - { cx1 = 2 * cur_x - last_cx; cy1 = 2 * cur_y - last_cy; } - else - { cx1 = cur_x; cy1 = cur_y; } - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 't') { x += cur_x; y += cur_y; } - hb_draw_quadratic_to (dfuncs, draw_data, &st, cx1, cy1, x, y); - last_cx = cx1; last_cy = cy1; - cur_x = x; cur_y = y; - break; - } - case 'A': case 'a': - { - float rx = fp.next_float (); - float ry = fp.next_float (); - float x_rot = fp.next_float (); - bool large_arc = fp.next_flag (); - bool sweep = fp.next_flag (); - float x = fp.next_float (); - float y = fp.next_float (); - if (cmd == 'a') { x += cur_x; y += cur_y; } - - if (fabsf (x - cur_x) < 1e-6f && fabsf (y - cur_y) < 1e-6f) - { - cur_x = x; cur_y = y; - break; - } - - float cx, cy, theta1, dtheta, adj_rx, adj_ry; - svg_arc_endpoint_to_center (cur_x, cur_y, x, y, - rx, ry, x_rot, - large_arc, sweep, - &cx, &cy, &theta1, &dtheta, - &adj_rx, &adj_ry); - - float phi = x_rot * (float) M_PI / 180.f; - svg_arc_to_cubics (dfuncs, draw_data, &st, - cx, cy, adj_rx, adj_ry, phi, theta1, dtheta); - cur_x = x; cur_y = y; - break; - } - case 'Z': case 'z': - hb_draw_close_path (dfuncs, draw_data, &st); - cur_x = start_x; - cur_y = start_y; - break; - - default: - fp.p++; - continue; - } - - last_cmd = cmd; - } -} - -static void -svg_rect_to_path (float x, float y, float w, float h, float rx, float ry, - hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - if (rx < 0.f || ry < 0.f) - return; - - if (rx <= 0 && ry <= 0) - { - hb_draw_move_to (dfuncs, draw_data, &st, x, y); - hb_draw_line_to (dfuncs, draw_data, &st, x + w, y); - hb_draw_line_to (dfuncs, draw_data, &st, x + w, y + h); - hb_draw_line_to (dfuncs, draw_data, &st, x, y + h); - hb_draw_close_path (dfuncs, draw_data, &st); - return; - } - - if (rx <= 0) rx = ry; - if (ry <= 0) ry = rx; - rx = hb_min (rx, w / 2); - ry = hb_min (ry, h / 2); - - float kx = rx * 0.5522847498f; - float ky = ry * 0.5522847498f; - - hb_draw_move_to (dfuncs, draw_data, &st, x + rx, y); - hb_draw_line_to (dfuncs, draw_data, &st, x + w - rx, y); - hb_draw_cubic_to (dfuncs, draw_data, &st, - x + w - rx + kx, y, - x + w, y + ry - ky, - x + w, y + ry); - hb_draw_line_to (dfuncs, draw_data, &st, x + w, y + h - ry); - hb_draw_cubic_to (dfuncs, draw_data, &st, - x + w, y + h - ry + ky, - x + w - rx + kx, y + h, - x + w - rx, y + h); - hb_draw_line_to (dfuncs, draw_data, &st, x + rx, y + h); - hb_draw_cubic_to (dfuncs, draw_data, &st, - x + rx - kx, y + h, - x, y + h - ry + ky, - x, y + h - ry); - hb_draw_line_to (dfuncs, draw_data, &st, x, y + ry); - hb_draw_cubic_to (dfuncs, draw_data, &st, - x, y + ry - ky, - x + rx - kx, y, - x + rx, y); - hb_draw_close_path (dfuncs, draw_data, &st); -} - -static void -svg_circle_to_path (float cx, float cy, float r, - hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - float k = r * 0.5522847498f; - - hb_draw_move_to (dfuncs, draw_data, &st, cx + r, cy); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx + r, cy + k, - cx + k, cy + r, - cx, cy + r); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx - k, cy + r, - cx - r, cy + k, - cx - r, cy); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx - r, cy - k, - cx - k, cy - r, - cx, cy - r); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx + k, cy - r, - cx + r, cy - k, - cx + r, cy); - hb_draw_close_path (dfuncs, draw_data, &st); -} - -static void -svg_ellipse_to_path (float cx, float cy, float rx, float ry, - hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - float kx = rx * 0.5522847498f; - float ky = ry * 0.5522847498f; - - hb_draw_move_to (dfuncs, draw_data, &st, cx + rx, cy); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx + rx, cy + ky, - cx + kx, cy + ry, - cx, cy + ry); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx - kx, cy + ry, - cx - rx, cy + ky, - cx - rx, cy); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx - rx, cy - ky, - cx - kx, cy - ry, - cx, cy - ry); - hb_draw_cubic_to (dfuncs, draw_data, &st, - cx + kx, cy - ry, - cx + rx, cy - ky, - cx + rx, cy); - hb_draw_close_path (dfuncs, draw_data, &st); -} - -static void -svg_line_to_path (float x1, float y1, float x2, float y2, - hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - hb_draw_move_to (dfuncs, draw_data, &st, x1, y1); - hb_draw_line_to (dfuncs, draw_data, &st, x2, y2); -} - -static void -svg_polygon_to_path (hb_svg_str_t points, bool close, - hb_draw_funcs_t *dfuncs, void *draw_data) -{ - hb_draw_state_t st = HB_DRAW_STATE_DEFAULT; - hb_svg_float_parser_t fp (points); - bool first = true; - while (fp.has_more ()) - { - float x = fp.next_float (); - float y = fp.next_float (); - if (first) - { - hb_draw_move_to (dfuncs, draw_data, &st, x, y); - first = false; - } - else - hb_draw_line_to (dfuncs, draw_data, &st, x, y); - } - if (close && !first) - hb_draw_close_path (dfuncs, draw_data, &st); -} - -void -hb_raster_svg_shape_path_emit (hb_draw_funcs_t *dfuncs, void *draw_data, void *user_data) -{ - hb_svg_shape_emit_data_t *shape = (hb_svg_shape_emit_data_t *) user_data; - switch (shape->type) - { - case hb_svg_shape_emit_data_t::SHAPE_PATH: - hb_raster_svg_parse_path_data (shape->str_data, dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_RECT: - svg_rect_to_path (shape->params[0], shape->params[1], - shape->params[2], shape->params[3], - shape->params[4], shape->params[5], - dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_CIRCLE: - svg_circle_to_path (shape->params[0], shape->params[1], shape->params[2], - dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_ELLIPSE: - svg_ellipse_to_path (shape->params[0], shape->params[1], - shape->params[2], shape->params[3], - dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_LINE: - svg_line_to_path (shape->params[0], shape->params[1], - shape->params[2], shape->params[3], - dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_POLYLINE: - svg_polygon_to_path (shape->str_data, false, dfuncs, draw_data); - break; - case hb_svg_shape_emit_data_t::SHAPE_POLYGON: - svg_polygon_to_path (shape->str_data, true, dfuncs, draw_data); - break; - } -} - -bool -hb_raster_svg_parse_shape_tag (hb_svg_xml_parser_t &parser, - hb_svg_shape_emit_data_t *shape) -{ - hb_svg_attr_view_t attrs (parser); - hb_svg_style_props_t style_props; - svg_parse_style_props (attrs.get ("style"), &style_props); - hb_svg_str_t tag = parser.tag_name; - if (tag.eq ("path")) - { - hb_svg_str_t d = svg_pick_attr_or_style (parser, style_props.d, "d"); - if (!d.len) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_PATH; - shape->str_data = d; - return true; - } - if (tag.eq ("rect")) - { - float w = svg_parse_float (svg_pick_attr_or_style (parser, style_props.width, "width")); - float h = svg_parse_float (svg_pick_attr_or_style (parser, style_props.height, "height")); - if (w <= 0 || h <= 0) return false; - float rx = svg_parse_float (svg_pick_attr_or_style (parser, style_props.rx, "rx")); - float ry = svg_parse_float (svg_pick_attr_or_style (parser, style_props.ry, "ry")); - if (rx < 0.f || ry < 0.f) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_RECT; - shape->params[0] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.x, "x")); - shape->params[1] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.y, "y")); - shape->params[2] = w; - shape->params[3] = h; - shape->params[4] = rx; - shape->params[5] = ry; - return true; - } - if (tag.eq ("circle")) - { - float r = svg_parse_float (svg_pick_attr_or_style (parser, style_props.r, "r")); - if (r <= 0) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_CIRCLE; - shape->params[0] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.cx, "cx")); - shape->params[1] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.cy, "cy")); - shape->params[2] = r; - return true; - } - if (tag.eq ("ellipse")) - { - float rx = svg_parse_float (svg_pick_attr_or_style (parser, style_props.rx, "rx")); - float ry = svg_parse_float (svg_pick_attr_or_style (parser, style_props.ry, "ry")); - if (rx <= 0 || ry <= 0) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_ELLIPSE; - shape->params[0] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.cx, "cx")); - shape->params[1] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.cy, "cy")); - shape->params[2] = rx; - shape->params[3] = ry; - return true; - } - if (tag.eq ("line")) - { - shape->type = hb_svg_shape_emit_data_t::SHAPE_LINE; - shape->params[0] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.x1, "x1")); - shape->params[1] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.y1, "y1")); - shape->params[2] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.x2, "x2")); - shape->params[3] = svg_parse_float (svg_pick_attr_or_style (parser, style_props.y2, "y2")); - return true; - } - if (tag.eq ("polyline")) - { - hb_svg_str_t points = svg_pick_attr_or_style (parser, style_props.points, "points"); - if (!points.len) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_POLYLINE; - shape->str_data = points; - return true; - } - if (tag.eq ("polygon")) - { - hb_svg_str_t points = svg_pick_attr_or_style (parser, style_props.points, "points"); - if (!points.len) return false; - shape->type = hb_svg_shape_emit_data_t::SHAPE_POLYGON; - shape->str_data = points; - return true; - } - return false; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.hh deleted file mode 100644 index 4497ddf1c6..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-parse.hh +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_PARSE_HH -#define HB_RASTER_SVG_PARSE_HH - -#include "hb.hh" - -#include "hb-raster-svg-base.hh" -#include "hb-draw.h" - -#include -#include - -enum hb_svg_token_type_t -{ - SVG_TOKEN_OPEN_TAG, - SVG_TOKEN_CLOSE_TAG, - SVG_TOKEN_SELF_CLOSE_TAG, - SVG_TOKEN_TEXT, - SVG_TOKEN_EOF -}; - -struct hb_svg_attr_t -{ - hb_svg_str_t name; - hb_svg_str_t value; -}; - -struct hb_svg_xml_parser_t -{ - enum { SVG_MAX_ATTRS_PER_TAG = 256 }; - - const char *p; - const char *end; - const char *tag_start = nullptr; - - hb_svg_str_t tag_name; - hb_vector_t attrs; - bool self_closing; - - hb_svg_xml_parser_t (const char *data, unsigned len) - : p (data), end (data + len), self_closing (false) {} - - void skip_ws () - { - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) - p++; - } - - hb_svg_str_t read_name () - { - const char *start = p; - while (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' && - *p != '>' && *p != '/' && *p != '=') - p++; - return {start, (unsigned) (p - start)}; - } - - hb_svg_str_t read_attr_value () - { - if (p >= end) return {}; - char quote = *p; - if (quote != '"' && quote != '\'') return {}; - p++; - const char *start = p; - while (p < end && *p != quote) - p++; - hb_svg_str_t val = {start, (unsigned) (p - start)}; - if (p < end) p++; /* skip closing quote */ - return val; - } - - void parse_attrs () - { - attrs.clear (); - while (p < end) - { - skip_ws (); - if (p >= end || *p == '>' || *p == '/') break; - hb_svg_str_t name = read_name (); - if (!name.len) { p++; continue; } - skip_ws (); - if (p < end && *p == '=') - { - p++; - skip_ws (); - hb_svg_str_t val = read_attr_value (); - if (attrs.length < SVG_MAX_ATTRS_PER_TAG) - { - hb_svg_attr_t attr = {name, val}; - attrs.push (attr); - } - } - else - { - if (attrs.length < SVG_MAX_ATTRS_PER_TAG) - { - hb_svg_attr_t attr = {name, {}}; - attrs.push (attr); - } - } - } - } - - hb_svg_token_type_t next () - { - while (p < end) - { - if (*p != '<') - { - while (p < end && *p != '<') p++; - continue; - } - - tag_start = p; - p++; /* skip '<' */ - if (p >= end) return SVG_TOKEN_EOF; - - if (*p == '!') - { - if (p + 2 < end && p[1] == '-' && p[2] == '-') - { - p += 3; - while (p + 2 < end && !(p[0] == '-' && p[1] == '-' && p[2] == '>')) - p++; - if (p + 2 < end) p += 3; - } - else - { - while (p < end && *p != '>') p++; - if (p < end) p++; - } - continue; - } - if (*p == '?') - { - while (p + 1 < end && !(p[0] == '?' && p[1] == '>')) - p++; - if (p + 1 < end) p += 2; - continue; - } - - if (*p == '/') - { - p++; - tag_name = read_name (); - while (p < end && *p != '>') p++; - if (p < end) p++; - attrs.clear (); - self_closing = false; - return SVG_TOKEN_CLOSE_TAG; - } - - tag_name = read_name (); - parse_attrs (); - - self_closing = false; - skip_ws (); - if (p < end && *p == '/') - { - self_closing = true; - p++; - } - if (p < end && *p == '>') - p++; - - return self_closing ? SVG_TOKEN_SELF_CLOSE_TAG : SVG_TOKEN_OPEN_TAG; - } - return SVG_TOKEN_EOF; - } - - hb_svg_str_t find_attr (const char *name) const - { - for (unsigned i = 0; i < attrs.length; i++) - if (attrs[i].name.eq (name)) - return attrs[i].value; - return {}; - } -}; - -static inline hb_svg_str_t -svg_pick_attr_or_style (const hb_svg_xml_parser_t &parser, - hb_svg_str_t style_value, - const char *attr_name) -{ - return style_value.is_null () ? parser.find_attr (attr_name) : style_value; -} - -struct hb_svg_attr_view_t -{ - const hb_svg_xml_parser_t &parser; - enum { CACHE_SIZE = 16 }; - struct entry_t - { - const char *name = nullptr; - hb_svg_str_t value; - }; - entry_t cache[CACHE_SIZE]; - unsigned cache_len = 0; - - hb_svg_attr_view_t (const hb_svg_xml_parser_t &p) : parser (p) {} - - hb_svg_str_t get (const char *name) - { - for (unsigned i = 0; i < cache_len; i++) - if (strcmp (cache[i].name, name) == 0) - return cache[i].value; - - hb_svg_str_t value = parser.find_attr (name); - if (cache_len < CACHE_SIZE) - { - cache[cache_len].name = name; - cache[cache_len].value = value; - cache_len++; - } - return value; - } -}; - -struct hb_svg_transform_t -{ - float xx = 1, yx = 0, xy = 0, yy = 1, dx = 0, dy = 0; - - void multiply (const hb_svg_transform_t &other) - { - float nxx = xx * other.xx + xy * other.yx; - float nyx = yx * other.xx + yy * other.yx; - float nxy = xx * other.xy + xy * other.yy; - float nyy = yx * other.xy + yy * other.yy; - float ndx = xx * other.dx + xy * other.dy + dx; - float ndy = yx * other.dx + yy * other.dy + dy; - xx = nxx; yx = nyx; xy = nxy; yy = nyy; dx = ndx; dy = ndy; - } -}; - -struct hb_svg_float_parser_t -{ - const char *p; - const char *end; - - hb_svg_float_parser_t (hb_svg_str_t s) : p (s.data), end (s.data + s.len) {} - - void skip_ws_comma () - { - while (p < end && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == ',')) - p++; - } - - bool has_more () const { return p < end; } - - float next_float () - { - skip_ws_comma (); - if (p >= end) return 0.f; - const char *start = p; - char buf[64]; - unsigned n = 0; - bool has_digit = false; - if (p < end && (*p == '-' || *p == '+')) - buf[n++] = *p++; - while (p < end && n < sizeof (buf) - 1 && *p >= '0' && *p <= '9') - { - buf[n++] = *p++; - has_digit = true; - } - if (p < end && n < sizeof (buf) - 1 && *p == '.') - { - buf[n++] = *p++; - while (p < end && n < sizeof (buf) - 1 && *p >= '0' && *p <= '9') - { - buf[n++] = *p++; - has_digit = true; - } - } - if (p < end && n < sizeof (buf) - 1 && (*p == 'e' || *p == 'E')) - { - buf[n++] = *p++; - if (p < end && n < sizeof (buf) - 1 && (*p == '+' || *p == '-')) - buf[n++] = *p++; - bool has_exp_digit = false; - while (p < end && n < sizeof (buf) - 1 && *p >= '0' && *p <= '9') - { - buf[n++] = *p++; - has_exp_digit = true; - } - if (!has_exp_digit) - { - p = start; - has_digit = false; - } - } - if (!has_digit) - { - if (p < end) p++; - return 0.f; - } - buf[n] = '\0'; - float v = strtof (buf, nullptr); - return isfinite (v) ? v : 0.f; - } - - bool next_flag () - { - skip_ws_comma (); - if (p >= end) return false; - bool v = *p != '0'; - p++; - return v; - } -}; - -static inline float -svg_parse_float (hb_svg_str_t s) -{ - return s.to_float (); -} - -struct hb_svg_shape_emit_data_t -{ - enum { SHAPE_PATH, SHAPE_RECT, SHAPE_CIRCLE, SHAPE_ELLIPSE, - SHAPE_LINE, SHAPE_POLYLINE, SHAPE_POLYGON } type; - hb_svg_str_t str_data; - float params[6]; -}; - -HB_INTERNAL bool hb_raster_svg_parse_transform (hb_svg_str_t s, hb_svg_transform_t *out); -HB_INTERNAL void hb_raster_svg_parse_path_data (hb_svg_str_t d, hb_draw_funcs_t *dfuncs, void *draw_data); -HB_INTERNAL void hb_raster_svg_shape_path_emit (hb_draw_funcs_t *dfuncs, void *draw_data, void *user_data); -HB_INTERNAL bool hb_raster_svg_parse_shape_tag (hb_svg_xml_parser_t &parser, hb_svg_shape_emit_data_t *shape); - -#endif /* HB_RASTER_SVG_PARSE_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-render.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-render.cc deleted file mode 100644 index 34a5714dd5..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-render.cc +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-face.hh" -#include "hb-raster-svg.hh" -#include "hb-raster-svg-base.hh" -#include "hb-raster-svg-parse.hh" -#include "hb-raster-svg-context.hh" -#include "hb-raster-svg-defs-scan.hh" -#include "hb-raster-svg-gradient.hh" -#include "hb-raster-svg-clip.hh" -#include "hb-raster-svg-bbox.hh" -#include "hb-raster-svg-fill.hh" -#include "hb-raster-svg-use.hh" - -#include -#include - -#ifndef HB_NO_RASTER_SVG - -#define SVG_MAX_DEPTH 32 - -/* - * 11. Element renderer — recursive SVG rendering - */ - -static void svg_render_element (hb_svg_render_context_t *ctx, - hb_svg_xml_parser_t &parser, - const struct hb_svg_cascade_t &inherited); - -/* Gradient def parsing lives in hb-raster-svg-gradient.* */ - -/* Clip-path defs and push helpers live in hb-raster-svg-clip.* */ - -/* Render a single shape element */ -static void -svg_render_shape (hb_svg_render_context_t *ctx, - hb_svg_shape_emit_data_t &shape, - const hb_svg_cascade_t &state, - hb_svg_str_t transform_str) -{ - bool has_transform = transform_str.len > 0; - bool has_opacity = state.opacity < 1.f; - bool has_clip_path = false; - - if (has_opacity) - ctx->push_group (); - - if (has_transform) - { - hb_svg_transform_t t; - hb_raster_svg_parse_transform (transform_str, &t); - ctx->push_transform (t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); - } - - hb_extents_t<> bbox; - bool has_bbox = hb_raster_svg_compute_shape_bbox (shape, &bbox); - has_clip_path = hb_raster_svg_push_clip_path_ref (ctx->paint, &ctx->defs, state.clip_path, - has_bbox ? &bbox : nullptr); - - /* Clip with shape path, then fill */ - hb_raster_paint_push_clip_path (ctx->paint, hb_raster_svg_shape_path_emit, &shape); - - /* Default fill is black */ - if (state.fill.is_null ()) - { - hb_color_t black = HB_COLOR (0, 0, 0, 255); - if (state.fill_opacity < 1.f) - black = HB_COLOR (0, 0, 0, (uint8_t) (255 * state.fill_opacity + 0.5f)); - ctx->paint_color (black); - } - else - { - hb_svg_fill_context_t fill_ctx = {ctx->paint, ctx->pfuncs, ctx->font, ctx->palette, &ctx->defs}; - hb_raster_svg_emit_fill (&fill_ctx, state.fill, state.fill_opacity, has_bbox ? &bbox : nullptr, state.color); - } - - ctx->pop_clip (); - if (has_clip_path) - ctx->pop_clip (); - - if (has_transform) - ctx->pop_transform (); - - if (has_opacity) - ctx->pop_group (HB_PAINT_COMPOSITE_MODE_SRC_OVER); -} - -static void -svg_render_container_element (hb_svg_render_context_t *ctx, - hb_svg_xml_parser_t &parser, - hb_svg_str_t tag, - bool self_closing, - const hb_svg_cascade_t &state, - hb_svg_str_t transform_str, - hb_svg_str_t clip_path_str) -{ - bool has_transform = transform_str.len > 0; - bool has_opacity = state.opacity < 1.f; - bool has_clip = false; - bool has_viewbox = false; - bool has_viewbox_transform = false; - bool has_svg_translate = false; - float svg_x = 0.f, svg_y = 0.f; - float viewport_w = 0.f, viewport_h = 0.f; - hb_svg_transform_t viewbox_t; - float vb_x = 0, vb_y = 0, vb_w = 0, vb_h = 0; - - if (tag.eq ("svg") || tag.eq ("symbol")) - { - hb_svg_style_props_t geom_style_props; - svg_parse_style_props (parser.find_attr ("style"), &geom_style_props); - - if (tag.eq ("svg")) - { - svg_x = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.x, "x")); - svg_y = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.y, "y")); - has_svg_translate = (svg_x != 0.f || svg_y != 0.f); - } - - hb_svg_str_t viewbox_str = parser.find_attr ("viewBox"); - if (hb_raster_svg_parse_viewbox (viewbox_str, &vb_x, &vb_y, &vb_w, &vb_h)) - { - has_viewbox = true; - - if (tag.eq ("svg")) - { - viewport_w = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.width, "width")); - viewport_h = hb_raster_svg_parse_non_percent_length (svg_pick_attr_or_style (parser, geom_style_props.height, "height")); - if (!(viewport_w > 0.f && viewport_h > 0.f)) - { - viewport_w = vb_w; - viewport_h = vb_h; - } - has_viewbox_transform = - hb_raster_svg_compute_viewbox_transform (viewport_w, viewport_h, - vb_x, vb_y, vb_w, vb_h, - parser.find_attr ("preserveAspectRatio"), - &viewbox_t); - } - } - } - - if (ctx->suppress_viewbox_once) - { - has_viewbox = false; - has_viewbox_transform = false; - ctx->suppress_viewbox_once = false; - } - - if (has_opacity) - ctx->push_group (); - - if (has_transform) - { - hb_svg_transform_t t; - hb_raster_svg_parse_transform (transform_str, &t); - ctx->push_transform (t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); - } - - if (has_svg_translate) - ctx->push_transform (1, 0, 0, 1, svg_x, svg_y); - - if (has_viewbox_transform) - ctx->push_transform (viewbox_t.xx, viewbox_t.yx, viewbox_t.xy, viewbox_t.yy, - viewbox_t.dx, viewbox_t.dy); - else if (has_viewbox && vb_w > 0 && vb_h > 0) - ctx->push_transform (1, 0, 0, 1, -vb_x, -vb_y); - - has_clip = hb_raster_svg_push_clip_path_ref (ctx->paint, &ctx->defs, clip_path_str, nullptr); - - if (!self_closing) - { - int depth = 1; - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - - if (tok == SVG_TOKEN_CLOSE_TAG) - { - depth--; - continue; - } - - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - { - hb_svg_str_t child_tag = parser.tag_name; - if (parser.tag_name.eq ("defs")) - { - if (tok != SVG_TOKEN_SELF_CLOSE_TAG) - { - hb_svg_defs_scan_context_t scan_ctx = { - &ctx->defs, ctx->pfuncs, ctx->paint, - ctx->foreground, hb_font_get_face (ctx->font), - ctx->palette, - ctx->doc_start, ctx->doc_len, - ctx->svg_accel, ctx->doc_cache - }; - hb_raster_svg_process_defs_element (&scan_ctx, parser); - } - continue; - } - svg_render_element (ctx, parser, state); - if (tok == SVG_TOKEN_OPEN_TAG && - !hb_raster_svg_tag_is_container_or_use (child_tag)) - { - /* Skip children of non-container elements we don't handle. */ - int skip_depth = 1; - while (skip_depth > 0) - { - hb_svg_token_type_t st = parser.next (); - if (st == SVG_TOKEN_EOF) break; - if (st == SVG_TOKEN_CLOSE_TAG) skip_depth--; - else if (st == SVG_TOKEN_OPEN_TAG) skip_depth++; - } - } - } - } - } - - if (has_viewbox_transform || (has_viewbox && vb_w > 0 && vb_h > 0)) - ctx->pop_transform (); - - if (has_svg_translate) - ctx->pop_transform (); - - if (has_clip) - ctx->pop_clip (); - - if (has_transform) - ctx->pop_transform (); - - if (has_opacity) - ctx->pop_group (HB_PAINT_COMPOSITE_MODE_SRC_OVER); -} - -static bool -svg_render_primitive_shape_element (hb_svg_render_context_t *ctx, - hb_svg_xml_parser_t &parser, - const hb_svg_cascade_t &state, - hb_svg_str_t transform_str) -{ - hb_svg_str_t tag = parser.tag_name; - if (!(tag.eq ("path") || tag.eq ("rect") || tag.eq ("circle") || - tag.eq ("ellipse") || tag.eq ("line") || tag.eq ("polyline") || - tag.eq ("polygon"))) - return false; - - hb_svg_shape_emit_data_t shape; - if (hb_raster_svg_parse_shape_tag (parser, &shape)) - svg_render_shape (ctx, shape, state, transform_str); - return true; -} - -static void -svg_render_use_callback (void *render_user, - hb_svg_xml_parser_t &parser, - const void *state, - bool viewport_mapped) -{ - hb_svg_render_context_t *ctx = (hb_svg_render_context_t *) render_user; - bool old_suppress = ctx->suppress_viewbox_once; - bool old_allow_symbol = ctx->allow_symbol_render_once; - if (viewport_mapped) - ctx->suppress_viewbox_once = true; - if (parser.tag_name.eq ("symbol")) - ctx->allow_symbol_render_once = true; - svg_render_element (ctx, parser, *(const hb_svg_cascade_t *) state); - ctx->suppress_viewbox_once = old_suppress; - ctx->allow_symbol_render_once = old_allow_symbol; -} - -static void -svg_skip_subtree (hb_svg_xml_parser_t &parser) -{ - int depth = 1; - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_CLOSE_TAG) depth--; - else if (tok == SVG_TOKEN_OPEN_TAG) depth++; - } -} - -/* Render one element (may be a container or shape) */ -static void -svg_render_element (hb_svg_render_context_t *ctx, - hb_svg_xml_parser_t &parser, - const hb_svg_cascade_t &inherited) -{ - if (ctx->depth >= SVG_MAX_DEPTH) return; - - const HB_UNUSED unsigned transform_depth = ctx->paint->transform_stack.length; - const HB_UNUSED unsigned clip_depth = ctx->paint->clip_stack.length; - const HB_UNUSED unsigned surface_depth = ctx->paint->surface_stack.length; - - ctx->depth++; - - hb_svg_str_t tag = parser.tag_name; - bool self_closing = parser.self_closing; - - /* Extract common attributes */ - hb_svg_str_t style = parser.find_attr ("style"); - hb_svg_style_props_t style_props; - svg_parse_style_props (style, &style_props); - hb_svg_str_t fill_attr = svg_pick_attr_or_style (parser, style_props.fill, "fill"); - hb_svg_str_t fill_opacity_str = svg_pick_attr_or_style (parser, style_props.fill_opacity, "fill-opacity"); - hb_svg_str_t opacity_str = svg_pick_attr_or_style (parser, style_props.opacity, "opacity"); - hb_svg_str_t transform_str = svg_pick_attr_or_style (parser, style_props.transform, "transform"); - hb_svg_str_t clip_path_attr = svg_pick_attr_or_style (parser, style_props.clip_path, "clip-path"); - hb_svg_str_t display_str = svg_pick_attr_or_style (parser, style_props.display, "display"); - hb_svg_str_t color_str = svg_pick_attr_or_style (parser, style_props.color, "color"); - hb_svg_str_t visibility_str = svg_pick_attr_or_style (parser, style_props.visibility, "visibility"); - - hb_svg_cascade_t state = inherited; - state.fill = (fill_attr.is_null () || svg_str_is_inherit (fill_attr)) ? inherited.fill : fill_attr; - state.fill_opacity = (fill_opacity_str.len && !svg_str_is_inherit (fill_opacity_str)) - ? svg_parse_float_clamped01 (fill_opacity_str) - : inherited.fill_opacity; - state.opacity = (opacity_str.len && !svg_str_is_inherit (opacity_str) && !svg_str_is_none (opacity_str)) - ? svg_parse_float_clamped01 (opacity_str) - : (svg_str_is_inherit (opacity_str) ? inherited.opacity : 1.f); - state.clip_path = (clip_path_attr.is_null () || svg_str_is_inherit (clip_path_attr)) - ? inherited.clip_path - : clip_path_attr; - if (svg_str_is_inherit (transform_str) || svg_str_is_none (transform_str)) - transform_str = {}; - state.color = inherited.color; - bool is_none = false; - if (color_str.len && !color_str.trim ().eq_ascii_ci ("inherit")) - state.color = hb_raster_svg_parse_color (color_str, ctx->pfuncs, ctx->paint, - inherited.color, hb_font_get_face (ctx->font), - ctx->palette, &is_none); - state.visibility = inherited.visibility; - hb_svg_str_t visibility_trim = visibility_str.trim (); - if (visibility_trim.len && !visibility_trim.eq_ascii_ci ("inherit")) - state.visibility = !(visibility_trim.eq_ascii_ci ("hidden") || - visibility_trim.eq_ascii_ci ("collapse")); - - if (display_str.trim ().eq_ascii_ci ("none")) - { - if (!self_closing) - svg_skip_subtree (parser); - ctx->depth--; - assert (ctx->paint->transform_stack.length == transform_depth); - assert (ctx->paint->clip_stack.length == clip_depth); - assert (ctx->paint->surface_stack.length == surface_depth); - return; - } - if (!state.visibility) - { - if (!self_closing) - svg_skip_subtree (parser); - ctx->depth--; - assert (ctx->paint->transform_stack.length == transform_depth); - assert (ctx->paint->clip_stack.length == clip_depth); - assert (ctx->paint->surface_stack.length == surface_depth); - return; - } - - if (tag.eq ("symbol") && !ctx->allow_symbol_render_once) - { - if (!self_closing) - svg_skip_subtree (parser); - ctx->depth--; - assert (ctx->paint->transform_stack.length == transform_depth); - assert (ctx->paint->clip_stack.length == clip_depth); - assert (ctx->paint->surface_stack.length == surface_depth); - return; - } - if (tag.eq ("symbol")) - ctx->allow_symbol_render_once = false; - - if (hb_raster_svg_tag_is_container (tag)) - svg_render_container_element (ctx, parser, tag, self_closing, - state, transform_str, state.clip_path); - else if (svg_render_primitive_shape_element (ctx, parser, state, transform_str)) - ; - else if (tag.eq ("use")) - { - hb_svg_use_context_t use_ctx = {ctx->paint, ctx->pfuncs, - ctx->doc_start, ctx->doc_len, - ctx->svg_accel, ctx->doc_cache, - &ctx->use_decycler}; - hb_raster_svg_render_use_element (&use_ctx, parser, &state, transform_str, - svg_render_use_callback, ctx); - } - - ctx->depth--; - - assert (ctx->paint->transform_stack.length == transform_depth); - assert (ctx->paint->clip_stack.length == clip_depth); - assert (ctx->paint->surface_stack.length == surface_depth); -} - - -/* - * 12. Entry point - */ - -hb_bool_t -hb_raster_svg_render (hb_raster_paint_t *paint, - hb_blob_t *blob, - hb_codepoint_t glyph, - hb_font_t *font, - unsigned palette, - hb_color_t foreground) -{ - unsigned data_len; - const char *data = hb_blob_get_data (blob, &data_len); - if (!data || !data_len) return false; - - hb_face_t *face = hb_font_get_face (font); - const OT::SVG::svg_doc_cache_t *doc_cache = nullptr; - unsigned doc_index = 0; - hb_codepoint_t start_glyph = HB_CODEPOINT_INVALID; - hb_codepoint_t end_glyph = HB_CODEPOINT_INVALID; - - if (face && - hb_ot_color_glyph_get_svg_document_index (face, glyph, &doc_index) && - hb_ot_color_get_svg_document_glyph_range (face, doc_index, &start_glyph, &end_glyph)) - doc_cache = face->table.SVG->get_or_create_doc_cache (blob, data, data_len, - doc_index, start_glyph, end_glyph); - - if (doc_cache) - data = face->table.SVG->doc_cache_get_svg (doc_cache, &data_len); - - hb_paint_funcs_t *pfuncs = hb_raster_paint_get_funcs (); - - hb_svg_render_context_t ctx; - ctx.paint = paint; - ctx.pfuncs = pfuncs; - ctx.font = font; - ctx.palette = palette; - ctx.foreground = foreground; - ctx.doc_start = data; - ctx.doc_len = data_len; - ctx.svg_accel = face ? face->table.SVG.get () : nullptr; - ctx.doc_cache = doc_cache; - - hb_svg_cascade_t initial_state; - initial_state.color = foreground; - - hb_svg_defs_scan_context_t scan_ctx = { - &ctx.defs, ctx.pfuncs, ctx.paint, - ctx.foreground, hb_font_get_face (ctx.font), - ctx.palette, - ctx.doc_start, ctx.doc_len, - ctx.svg_accel, ctx.doc_cache - }; - hb_raster_svg_collect_defs (&scan_ctx, data, data_len); - - bool found_glyph = false; - unsigned glyph_start = 0, glyph_end = 0; - if (doc_cache && face->table.SVG->doc_cache_get_glyph_span (doc_cache, glyph, &glyph_start, &glyph_end)) - { - hb_svg_xml_parser_t parser (data + glyph_start, glyph_end - glyph_start); - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - { - hb_paint_push_font_transform (ctx.pfuncs, ctx.paint, font); - ctx.push_transform (1, 0, 0, -1, 0, 0); - svg_render_element (&ctx, parser, initial_state); - ctx.pop_transform (); - hb_paint_pop_transform (ctx.pfuncs, ctx.paint); - found_glyph = true; - } - } - else - { - /* Fallback for malformed/uncached docs: linear scan by glyph id. */ - char glyph_id_str[32]; - int glyph_id_len = snprintf (glyph_id_str, sizeof (glyph_id_str), "glyph%u", glyph); - if (glyph_id_len <= 0 || (unsigned) glyph_id_len >= sizeof (glyph_id_str)) - return false; - hb_svg_xml_parser_t parser (data, data_len); - while (true) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - { - hb_svg_str_t id = parser.find_attr ("id"); - if (id.len) - { - if (id.len == (unsigned) glyph_id_len && - 0 == memcmp (id.data, glyph_id_str, (unsigned) glyph_id_len)) - { - hb_paint_push_font_transform (ctx.pfuncs, ctx.paint, font); - ctx.push_transform (1, 0, 0, -1, 0, 0); - svg_render_element (&ctx, parser, initial_state); - ctx.pop_transform (); - hb_paint_pop_transform (ctx.pfuncs, ctx.paint); - found_glyph = true; - break; - } - } - } - } - } - - return found_glyph; -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.cc deleted file mode 100644 index b649612307..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_NO_RASTER_SVG - -#include "hb.hh" - -#include "hb-raster-svg-use.hh" - -#include "hb-raster-svg-base.hh" - -void -hb_raster_svg_render_use_element (const hb_svg_use_context_t *ctx, - hb_svg_xml_parser_t &parser, - const void *state, - hb_svg_str_t transform_str, - hb_svg_use_render_cb_t render_cb, - void *render_user) -{ - hb_svg_str_t href = hb_raster_svg_find_href_attr (parser); - - hb_svg_str_t ref_id; - if (!hb_raster_svg_parse_local_id_ref (href, &ref_id, nullptr)) - return; - - float use_x = 0.f, use_y = 0.f, use_w = 0.f, use_h = 0.f; - hb_raster_svg_parse_use_geometry (parser, &use_x, &use_y, &use_w, &use_h); - - bool has_translate = (use_x != 0.f || use_y != 0.f); - bool has_use_transform = transform_str.len > 0; - - if (has_use_transform) - { - hb_svg_transform_t t; - hb_raster_svg_parse_transform (transform_str, &t); - hb_paint_push_transform (ctx->pfuncs, ctx->paint, t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); - } - - if (has_translate) - hb_paint_push_transform (ctx->pfuncs, ctx->paint, 1, 0, 0, 1, use_x, use_y); - - const char *found = nullptr; - hb_raster_svg_find_element_by_id (ctx->doc_start, ctx->doc_len, ctx->svg_accel, ctx->doc_cache, - ref_id, &found); - - if (found) - { - bool can_render = true; - hb_decycler_node_t node (*ctx->use_decycler); - if (unlikely (!node.visit ((uintptr_t) found))) - can_render = false; - - if (can_render) - { - unsigned remaining = ctx->doc_start + ctx->doc_len - found; - hb_svg_xml_parser_t ref_parser (found, remaining); - hb_svg_token_type_t tok = ref_parser.next (); - if (tok == SVG_TOKEN_OPEN_TAG || tok == SVG_TOKEN_SELF_CLOSE_TAG) - { - bool has_viewport_scale = false; - hb_svg_transform_t t; - if (hb_raster_svg_compute_use_target_viewbox_transform (ref_parser, use_w, use_h, &t)) - { - hb_paint_push_transform (ctx->pfuncs, ctx->paint, t.xx, t.yx, t.xy, t.yy, t.dx, t.dy); - has_viewport_scale = true; - } - render_cb (render_user, ref_parser, state, has_viewport_scale); - if (has_viewport_scale) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - } - } - } - - if (has_translate) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); - - if (has_use_transform) - hb_paint_pop_transform (ctx->pfuncs, ctx->paint); -} - -#endif /* !HB_NO_RASTER_SVG */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.hh deleted file mode 100644 index aa81f4a013..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg-use.hh +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_USE_HH -#define HB_RASTER_SVG_USE_HH - -#include "hb.hh" - -#include "hb-raster-svg-context.hh" -#include "hb-raster-svg-parse.hh" - -typedef void (*hb_svg_use_render_cb_t) (void *render_user, - hb_svg_xml_parser_t &parser, - const void *state, - bool viewport_mapped); - -HB_INTERNAL void -hb_raster_svg_render_use_element (const hb_svg_use_context_t *ctx, - hb_svg_xml_parser_t &parser, - const void *state, - hb_svg_str_t transform_str, - hb_svg_use_render_cb_t render_cb, - void *render_user); - -#endif /* HB_RASTER_SVG_USE_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg.hh deleted file mode 100644 index 3b723f7c6d..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-svg.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_SVG_HH -#define HB_RASTER_SVG_HH - -#include "hb.hh" - -struct hb_raster_paint_t; - -/* Callback type: emits SVG path draw commands to the given draw funcs */ -typedef void (*hb_raster_svg_path_func_t) (hb_draw_funcs_t *dfuncs, - void *draw_data, - void *user_data); - -/* Push clip from arbitrary path (reuses push_clip_glyph logic) */ -HB_INTERNAL void -hb_raster_paint_push_clip_path (hb_raster_paint_t *c, - hb_raster_svg_path_func_t func, - void *user_data); - -/* Render SVG document for a specific glyph */ -#ifndef HB_NO_RASTER_SVG -HB_INTERNAL hb_bool_t -hb_raster_svg_render (hb_raster_paint_t *paint, - hb_blob_t *blob, - hb_codepoint_t glyph, - hb_font_t *font, - unsigned palette, - hb_color_t foreground); -#else -static inline hb_bool_t -hb_raster_svg_render (hb_raster_paint_t *paint HB_UNUSED, - hb_blob_t *blob HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - hb_font_t *font HB_UNUSED, - unsigned palette HB_UNUSED, - hb_color_t foreground HB_UNUSED) -{ - return false; -} -#endif - - -#endif /* HB_RASTER_SVG_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-utils.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-utils.hh deleted file mode 100644 index 852aee8445..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster-utils.hh +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_RASTER_HH -#define HB_RASTER_HH - -#include "hb.hh" - -/* Shared pixel helpers (used by paint and image compositing). */ - -static HB_ALWAYS_INLINE uint8_t -hb_raster_div255 (unsigned a) -{ - if (true) - { - // An approximation. Slightly faster. - // https://github.com/linebender/vello/blob/ab58009c8289e83689cd0effc4e34d1c6e8b51f5/sparse_strips/vello_cpu/src/util.rs#L10-L63 - return (a + 255) >> 8; - } - - return (uint8_t) ((a + 128 + ((a + 128) >> 8)) >> 8); -} - -static HB_ALWAYS_INLINE uint32_t -hb_raster_pack_pixel (uint8_t b, uint8_t g, uint8_t r, uint8_t a) -{ - return (uint32_t) b | ((uint32_t) g << 8) | ((uint32_t) r << 16) | ((uint32_t) a << 24); -} - -/* SRC_OVER: premultiplied src over premultiplied dst. */ -static HB_ALWAYS_INLINE uint32_t -hb_raster_src_over (uint32_t src, uint32_t dst) -{ - uint8_t sa = (uint8_t) (src >> 24); - if (sa == 255) return src; - if (sa == 0) return dst; - unsigned inv_sa = 255 - sa; - uint8_t rb = hb_raster_div255 ((dst & 0xFF) * inv_sa) + (uint8_t) (src & 0xFF); - uint8_t rg = hb_raster_div255 (((dst >> 8) & 0xFF) * inv_sa) + (uint8_t) ((src >> 8) & 0xFF); - uint8_t rr = hb_raster_div255 (((dst >> 16) & 0xFF) * inv_sa) + (uint8_t) ((src >> 16) & 0xFF); - uint8_t ra = hb_raster_div255 (((dst >> 24) & 0xFF) * inv_sa) + sa; - return (uint32_t) rb | ((uint32_t) rg << 8) | ((uint32_t) rr << 16) | ((uint32_t) ra << 24); -} - -/* Scale a premultiplied pixel by an alpha [0,255]. */ -static HB_ALWAYS_INLINE uint32_t -hb_raster_alpha_mul (uint32_t px, unsigned a) -{ - if (a == 255) return px; - if (a == 0) return 0; - uint8_t rb = hb_raster_div255 ((px & 0xFF) * a); - uint8_t rg = hb_raster_div255 (((px >> 8) & 0xFF) * a); - uint8_t rr = hb_raster_div255 (((px >> 16) & 0xFF) * a); - uint8_t ra = hb_raster_div255 (((px >> 24) & 0xFF) * a); - return (uint32_t) rb | ((uint32_t) rg << 8) | ((uint32_t) rr << 16) | ((uint32_t) ra << 24); -} - -#endif /* HB_RASTER_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.cc index 7c56983b48..815ce2b718 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.cc @@ -38,18 +38,20 @@ * * #hb_raster_draw_t rasterizes outline geometry and always outputs * @HB_RASTER_FORMAT_A8. Typical flow: - * ``` + * + * |[ * hb_raster_draw_t *draw = hb_raster_draw_create_or_fail (); * hb_raster_draw_set_scale_factor (draw, 64.f, 64.f); * hb_raster_draw_set_transform (draw, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f); * hb_raster_draw_set_glyph_extents (draw, &glyph_extents); * hb_raster_draw_glyph (draw, font, gid, pen_x, pen_y); * hb_raster_image_t *mask = hb_raster_draw_render (draw); - * ``` + * ]| * * #hb_raster_paint_t renders color paint graphs and always outputs * @HB_RASTER_FORMAT_BGRA32. Typical flow: - * ``` + * + * |[ * hb_raster_paint_t *paint = hb_raster_paint_create_or_fail (); * hb_raster_paint_set_scale_factor (paint, 64.f, 64.f); * hb_raster_paint_set_transform (paint, 1.f, 0.f, 0.f, 1.f, 0.f, 0.f); @@ -57,9 +59,9 @@ * hb_glyph_extents_t glyph_extents; * hb_font_get_glyph_extents (font, gid, &glyph_extents); * hb_raster_paint_set_glyph_extents (paint, &glyph_extents); - * hb_raster_paint_glyph (paint, font, gid, pen_x, pen_y, 0, foreground); + * hb_raster_paint_glyph (paint, font, gid, pen_x, pen_y); * hb_raster_image_t *img = hb_raster_paint_render (paint); - * ``` + * ]| * * In both modes, set extents explicitly (or via glyph extents) before * rendering to avoid implicit allocations and to get deterministic bounds. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.h index f321cb4bd0..523c44ffa5 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-raster.h @@ -96,7 +96,7 @@ hb_raster_image_set_user_data (hb_raster_image_t *image, hb_bool_t replace); HB_EXTERN void * -hb_raster_image_get_user_data (hb_raster_image_t *image, +hb_raster_image_get_user_data (const hb_raster_image_t *image, hb_user_data_key_t *key); HB_EXTERN hb_bool_t @@ -108,14 +108,21 @@ HB_EXTERN void hb_raster_image_clear (hb_raster_image_t *image); HB_EXTERN const uint8_t * -hb_raster_image_get_buffer (hb_raster_image_t *image); +hb_raster_image_get_buffer (const hb_raster_image_t *image); HB_EXTERN void -hb_raster_image_get_extents (hb_raster_image_t *image, +hb_raster_image_get_extents (const hb_raster_image_t *image, hb_raster_extents_t *extents); HB_EXTERN hb_raster_format_t -hb_raster_image_get_format (hb_raster_image_t *image); +hb_raster_image_get_format (const hb_raster_image_t *image); + +HB_EXTERN hb_bool_t +hb_raster_image_deserialize_from_png_or_fail (hb_raster_image_t *image, + hb_blob_t *png); + +HB_EXTERN hb_blob_t * +hb_raster_image_serialize_to_png_or_fail (const hb_raster_image_t *image); /* hb_raster_draw_t */ @@ -148,7 +155,7 @@ hb_raster_draw_set_user_data (hb_raster_draw_t *draw, hb_bool_t replace); HB_EXTERN void * -hb_raster_draw_get_user_data (hb_raster_draw_t *draw, +hb_raster_draw_get_user_data (const hb_raster_draw_t *draw, hb_user_data_key_t *key); HB_EXTERN void @@ -157,28 +164,28 @@ hb_raster_draw_set_transform (hb_raster_draw_t *draw, float xy, float yy, float dx, float dy); +HB_EXTERN void +hb_raster_draw_get_transform (const hb_raster_draw_t *draw, + float *xx, float *yx, + float *xy, float *yy, + float *dx, float *dy); + HB_EXTERN void hb_raster_draw_set_scale_factor (hb_raster_draw_t *draw, float x_scale_factor, float y_scale_factor); HB_EXTERN void -hb_raster_draw_get_scale_factor (hb_raster_draw_t *draw, +hb_raster_draw_get_scale_factor (const hb_raster_draw_t *draw, float *x_scale_factor, float *y_scale_factor); -HB_EXTERN void -hb_raster_draw_get_transform (hb_raster_draw_t *draw, - float *xx, float *yx, - float *xy, float *yy, - float *dx, float *dy); - HB_EXTERN void hb_raster_draw_set_extents (hb_raster_draw_t *draw, const hb_raster_extents_t *extents); HB_EXTERN hb_bool_t -hb_raster_draw_get_extents (hb_raster_draw_t *draw, +hb_raster_draw_get_extents (const hb_raster_draw_t *draw, hb_raster_extents_t *extents); HB_EXTERN hb_bool_t @@ -186,18 +193,24 @@ hb_raster_draw_set_glyph_extents (hb_raster_draw_t *draw, const hb_glyph_extents_t *glyph_extents); HB_EXTERN hb_draw_funcs_t * -hb_raster_draw_get_funcs (void); +hb_raster_draw_get_funcs (const hb_raster_draw_t *draw); HB_EXTERN void hb_raster_draw_glyph (hb_raster_draw_t *draw, hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y); + hb_codepoint_t glyph); + +HB_EXTERN hb_bool_t +hb_raster_draw_glyph_or_fail (hb_raster_draw_t *draw, + hb_font_t *font, + hb_codepoint_t glyph); HB_EXTERN hb_raster_image_t * hb_raster_draw_render (hb_raster_draw_t *draw); +HB_EXTERN void +hb_raster_draw_clear (hb_raster_draw_t *draw); + HB_EXTERN void hb_raster_draw_reset (hb_raster_draw_t *draw); @@ -237,7 +250,7 @@ hb_raster_paint_set_user_data (hb_raster_paint_t *paint, hb_bool_t replace); HB_EXTERN void * -hb_raster_paint_get_user_data (hb_raster_paint_t *paint, +hb_raster_paint_get_user_data (const hb_raster_paint_t *paint, hb_user_data_key_t *key); HB_EXTERN void @@ -247,7 +260,7 @@ hb_raster_paint_set_transform (hb_raster_paint_t *paint, float dx, float dy); HB_EXTERN void -hb_raster_paint_get_transform (hb_raster_paint_t *paint, +hb_raster_paint_get_transform (const hb_raster_paint_t *paint, float *xx, float *yx, float *xy, float *yy, float *dx, float *dy); @@ -258,7 +271,7 @@ hb_raster_paint_set_scale_factor (hb_raster_paint_t *paint, float y_scale_factor); HB_EXTERN void -hb_raster_paint_get_scale_factor (hb_raster_paint_t *paint, +hb_raster_paint_get_scale_factor (const hb_raster_paint_t *paint, float *x_scale_factor, float *y_scale_factor); @@ -267,7 +280,7 @@ hb_raster_paint_set_extents (hb_raster_paint_t *paint, const hb_raster_extents_t *extents); HB_EXTERN hb_bool_t -hb_raster_paint_get_extents (hb_raster_paint_t *paint, +hb_raster_paint_get_extents (const hb_raster_paint_t *paint, hb_raster_extents_t *extents); HB_EXTERN hb_bool_t @@ -278,6 +291,23 @@ HB_EXTERN void hb_raster_paint_set_foreground (hb_raster_paint_t *paint, hb_color_t foreground); +HB_EXTERN hb_color_t +hb_raster_paint_get_foreground (const hb_raster_paint_t *paint); + +HB_EXTERN void +hb_raster_paint_set_background (hb_raster_paint_t *paint, + hb_color_t background); + +HB_EXTERN hb_color_t +hb_raster_paint_get_background (const hb_raster_paint_t *paint); + +HB_EXTERN void +hb_raster_paint_set_palette (hb_raster_paint_t *paint, + unsigned palette); + +HB_EXTERN unsigned +hb_raster_paint_get_palette (const hb_raster_paint_t *paint); + HB_EXTERN void hb_raster_paint_clear_custom_palette_colors (hb_raster_paint_t *paint); @@ -287,20 +317,24 @@ hb_raster_paint_set_custom_palette_color (hb_raster_paint_t *paint, hb_color_t color); HB_EXTERN hb_paint_funcs_t * -hb_raster_paint_get_funcs (void); +hb_raster_paint_get_funcs (const hb_raster_paint_t *paint); -HB_EXTERN hb_bool_t +HB_EXTERN void hb_raster_paint_glyph (hb_raster_paint_t *paint, hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y, - unsigned palette, - hb_color_t foreground); + hb_codepoint_t glyph); + +HB_EXTERN hb_bool_t +hb_raster_paint_glyph_or_fail (hb_raster_paint_t *paint, + hb_font_t *font, + hb_codepoint_t glyph); HB_EXTERN hb_raster_image_t * hb_raster_paint_render (hb_raster_paint_t *paint); +HB_EXTERN void +hb_raster_paint_clear (hb_raster_paint_t *paint); + HB_EXTERN void hb_raster_paint_reset (hb_raster_paint_t *paint); @@ -311,4 +345,13 @@ hb_raster_paint_recycle_image (hb_raster_paint_t *paint, HB_END_DECLS + +#if defined(__cplusplus) && defined(HB_CPLUSPLUS_HH) +namespace hb { +HB_DEFINE_VTABLE (raster_image, nullptr); +HB_DEFINE_VTABLE (raster_draw, nullptr); +HB_DEFINE_VTABLE (raster_paint, nullptr); +} // namespace hb +#endif + #endif /* HB_RASTER_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh index 7d118b5216..b5dfae1996 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh @@ -389,20 +389,21 @@ hb_resolve_graph_overflows (hb_tag_t table_tag, } unsigned round = 0; + unsigned total_iterations = 0; hb_vector_t overflows; // TODO(garretrieger): select a good limit for max rounds. while (!sorted_graph.in_error () && graph::will_overflow (sorted_graph, &overflows) - && round < max_rounds) { + && round < max_rounds + && total_iterations < HB_REPACKER_MAX_ITERATIONS) { DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %u ===", round); print_overflows (sorted_graph, overflows); + total_iterations++; hb_set_t priority_bumped_parents; if (!_try_isolating_subgraphs (overflows, sorted_graph)) { - // Don't count space isolation towards round limit. Only increment - // round counter if space isolation made no changes. round++; if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph)) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-static.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-static.cc index 06cc80b5f3..78713b2204 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-static.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-static.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_STATIC_CC +#define HB_STATIC_CC +#ifdef HB_STATIC_CC /* Pacify -Wunused-macros. */ + #include "hb.hh" #include "hb-open-type.hh" @@ -114,3 +118,6 @@ hb_face_t::load_upem () const } #endif + +#endif /* HB_STATIC_CC pacify */ +#endif /* HB_STATIC_CC guard */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc index 5e4ea5fe7c..96e148afc1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc @@ -68,7 +68,6 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* use hb_set to determine the subset of font dicts */ hb_set_t set; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; - hb_pair_t last_range {0, 0}; auto it = hb_iter (plan->new_to_old_gid_list); auto _ = *it; for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++) @@ -84,9 +83,8 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ old_glyph = gid; } - if (old_glyph >= last_range.second) - last_range = src.get_fd_range (old_glyph); - unsigned fd = last_range.first; + auto fd_range = src.get_fd_range (old_glyph); + unsigned fd = fd_range.first; if (fd != prev_fd) { @@ -96,7 +94,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, fdselect_ranges.push (code_pair_t { fd, gid }); if (gid == old_glyph) - gid = hb_min (_.first - 1, last_range.second - 1); + gid = hb_min (_.first - 1, fd_range.second - 1); } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc index d080e0a275..ba71e4cc88 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc @@ -431,7 +431,8 @@ struct cff1_subset_plan unsigned code, last_code = CFF_UNDEF_CODE - 1; hb_vector_t supp_codes; - if (unlikely (!subset_enc_code_ranges.resize (0))) + subset_enc_code_ranges.clear (); + if (unlikely (subset_enc_code_ranges.in_error ())) { plan->check_success (false); return; @@ -496,7 +497,8 @@ struct cff1_subset_plan unsigned int size0, size_ranges; unsigned last_sid = CFF_UNDEF_CODE - 1; - if (unlikely (!subset_charset_ranges.resize (0))) + subset_charset_ranges.clear (); + if (unlikely (subset_charset_ranges.in_error ())) { plan->check_success (false); return false; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc index 59748a4b26..262eeb1aba 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc @@ -686,7 +686,7 @@ _serialize_cff1_charstrings (hb_serialize_context_t *c, (cff1_charstrings[i].tail () != 0x0e && cff1_charstrings[i].tail () != 0x0b)) { // Append endchar operator - if (unlikely (!cff1_charstrings[i].push (0x0e))) + if (unlikely (!cff1_charstrings[i].push_or_fail (0x0e))) { c->pop_discard (); return false; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc index 11aefded2c..c838240cda 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc @@ -370,7 +370,8 @@ double renormalizeValue (double v, const Triple &triple, const TripleDistances &triple_distances, bool extrapolate) { double lower = triple.minimum, def = triple.middle, upper = triple.maximum; - assert (lower <= def && def <= upper); + if (unlikely (!(lower <= def && def <= upper))) + return hb_clamp (v, -1.0, +1.0); if (!extrapolate) v = hb_clamp (v, lower, upper); @@ -384,14 +385,26 @@ double renormalizeValue (double v, const Triple &triple, /* default >= 0 and v != default */ if (v > def) - return (v - def) / (upper - def); + { + double positive_range = upper - def; + if (unlikely (!positive_range)) + return +1.0; + return (v - def) / positive_range; + } /* v < def */ if (lower >= 0.0) - return (v - def) / (def - lower); + { + double negative_range = def - lower; + if (unlikely (!negative_range)) + return -1.0; + return (v - def) / negative_range; + } /* lower < 0 and v < default */ double total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def; + if (unlikely (!total_distance)) + return 0.0; double v_distance; if (v >= 0.0) @@ -407,9 +420,19 @@ rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distance rebase_tent_result_t &out, rebase_tent_result_t &scratch) { - assert (-1.0 <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.0); - assert (-2.0 <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.0); - assert (tent.middle != 0.0); + if (unlikely (!(-1.0 <= axisLimit.minimum && + axisLimit.minimum <= axisLimit.middle && + axisLimit.middle <= axisLimit.maximum && + axisLimit.maximum <= +1.0) || + !(-2.0 <= tent.minimum && + tent.minimum <= tent.middle && + tent.middle <= tent.maximum && + tent.maximum <= +2.0) || + tent.middle == 0.0)) + { + out.reset (); + return; + } rebase_tent_result_t &sols = scratch; _solve (tent, axisLimit, sols); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc index 3984cfb866..12d3888e33 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset-table-cff.cc @@ -89,15 +89,15 @@ static hb_blob_t* get_charstrings_index(accel_t& accel) { /** * hb_subset_cff_get_charstring_data: * @face: A face object - * @glyph_index: Glyph index to get data for. + * @glyph: Glyph index to get data for. * * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. * * XSince: EXPERIMENTAL **/ HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff1, glyph_index); +hb_subset_cff_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph) { + return get_charstrings_data(*face->table.cff1, glyph); } /** @@ -116,15 +116,15 @@ hb_subset_cff_get_charstrings_index (hb_face_t* face) { /** * hb_subset_cff2_get_charstring_data: * @face: A face object - * @glyph_index: Glyph index to get data for. + * @glyph: Glyph index to get data for. * * Returns the raw outline data from the CFF/CFF2 table associated with the given glyph index. * * XSince: EXPERIMENTAL **/ HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph_index) { - return get_charstrings_data(*face->table.cff2, glyph_index); +hb_subset_cff2_get_charstring_data(hb_face_t* face, hb_codepoint_t glyph) { + return get_charstrings_data(*face->table.cff2, glyph); } /** diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset.h index 2b9b2a2263..49cd12763d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-subset.h @@ -86,7 +86,7 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; * included at the end of the font to keep the number of glyphs unchanged. * @HB_SUBSET_FLAGS_DOWNGRADE_CFF2: If set and instantiating a variable font, * convert the output CFF2 table to CFF1. This enables compatibility with older - * renderers that don't support CFF2. Since: REPLACEME + * renderers that don't support CFF2. Since: 13.0.0 * * List of boolean properties that can be configured on the subset input. * @@ -243,13 +243,13 @@ hb_subset_input_override_name_table (hb_subset_input_t *input, */ HB_EXTERN hb_blob_t* -hb_subset_cff_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); +hb_subset_cff_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph); HB_EXTERN hb_blob_t* hb_subset_cff_get_charstrings_index (hb_face_t* face); HB_EXTERN hb_blob_t* -hb_subset_cff2_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph_index); +hb_subset_cff2_get_charstring_data (hb_face_t* face, hb_codepoint_t glyph); HB_EXTERN hb_blob_t* hb_subset_cff2_get_charstrings_index (hb_face_t* face); @@ -298,4 +298,12 @@ hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, HB_END_DECLS + +#if defined(__cplusplus) && defined(HB_CPLUSPLUS_HH) +namespace hb { +HB_DEFINE_VTABLE (subset_input, nullptr); +HB_DEFINE_VTABLE (subset_plan, nullptr); +} // namespace hb +#endif + #endif /* HB_SUBSET_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc index aa2735bedb..a157052fdc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc @@ -376,8 +376,12 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ + auto destroy_guard = hb_make_scope_guard ([&]() { \ + if (destroy) destroy (user_data); \ + }); \ + \ if (hb_object_is_immutable (ufuncs)) \ - goto fail; \ + return; \ \ if (!func) \ { \ @@ -396,11 +400,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \ ufuncs->func.name = ufuncs->parent->func.name; \ ufuncs->user_data.name = user_data; \ ufuncs->destroy.name = destroy; \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + destroy_guard.release (); \ } HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc index 1b8ac367e1..cbef494979 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc @@ -321,7 +321,7 @@ _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen) /* Destroys blob. */ static hb_blob_t * -_hb_rename_font (hb_blob_t *blob, wchar_t *new_name) +_hb_rename_font (hb_blob_t *blob_in, wchar_t *new_name) { /* Create a copy of the font data, with the 'name' table replaced by a * table that names the font with our private F_* name created above. @@ -332,7 +332,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) * full, PS. All of them point to the same name data with our unique name. */ - blob = hb_sanitize_context_t ().sanitize_blob (blob); + hb_unique_ptr_t blob (hb_sanitize_context_t ().sanitize_blob (blob_in)); unsigned int length, new_length, name_str_len; const char *orig_sfnt_data = hb_blob_get_data (blob, &length); @@ -350,10 +350,8 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) new_length = name_table_offset + padded_name_table_length; void *new_sfnt_data = hb_calloc (1, new_length); if (!new_sfnt_data) - { - hb_blob_destroy (blob); return nullptr; - } + auto sfnt_guard = hb_make_scope_guard ([&]() { hb_free (new_sfnt_data); }); hb_memcpy(new_sfnt_data, orig_sfnt_data, length); @@ -397,18 +395,14 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) record.length = name_table_length; } else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */ - { - hb_free (new_sfnt_data); - hb_blob_destroy (blob); return nullptr; - } } /* The checkSumAdjustment field in the 'head' table is now wrong, * but that doesn't actually seem to cause any problems so we don't * bother. */ - hb_blob_destroy (blob); + sfnt_guard.release (); return hb_blob_create ((const char *) new_sfnt_data, new_length, HB_MEMORY_MODE_WRITABLE, new_sfnt_data, hb_free); } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-draw.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-draw.cc deleted file mode 100644 index 54704f1a9c..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-draw.cc +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-vector.h" -#include "hb-blob.hh" -#include "hb-geometry.hh" -#include "hb-machinery.hh" -#include "hb-map.hh" -#include "hb-vector-svg-path.hh" -#include "hb-vector-svg-subset.hh" -#include "hb-vector-svg-utils.hh" - -#include -#include -#include - - -static bool -hb_svg_append_str (hb_vector_t *buf, const char *s) -{ - return hb_svg_append_len (buf, s, (unsigned) strlen (s)); -} - -static bool -hb_svg_append_unsigned (hb_vector_t *buf, unsigned v) -{ - char tmp[10]; - unsigned n = 0; - do { - tmp[n++] = (char) ('0' + (v % 10)); - v /= 10; - } while (v); - - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + n)))) - return false; - - for (unsigned i = 0; i < n; i++) - buf->arrayZ[old_len + i] = tmp[n - 1 - i]; - return true; -} - -static bool -hb_svg_append_hex_byte (hb_vector_t *buf, unsigned v) -{ - static const char hex[] = "0123456789ABCDEF"; - char tmp[2] = {hex[(v >> 4) & 15], hex[v & 15]}; - return hb_svg_append_len (buf, tmp, 2); -} - -HB_UNUSED static bool -hb_svg_append_base64 (hb_vector_t *buf, - const uint8_t *data, - unsigned len) -{ - static const char b64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - unsigned out_len = ((len + 2) / 3) * 4; - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + out_len)))) - return false; - - char *dst = buf->arrayZ + old_len; - unsigned di = 0; - unsigned i = 0; - while (i + 2 < len) - { - unsigned v = ((unsigned) data[i] << 16) | - ((unsigned) data[i + 1] << 8) | - ((unsigned) data[i + 2]); - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = b64[(v >> 6) & 63]; - dst[di++] = b64[v & 63]; - i += 3; - } - - if (i < len) - { - unsigned v = (unsigned) data[i] << 16; - if (i + 1 < len) - v |= (unsigned) data[i + 1] << 8; - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = (i + 1 < len) ? b64[(v >> 6) & 63] : '='; - dst[di++] = '='; - } - - return true; -} - -HB_UNUSED static inline bool -hb_svg_buffer_contains (const hb_vector_t &buf, const char *needle) -{ - unsigned nlen = (unsigned) strlen (needle); - if (!nlen || buf.length < nlen) - return false; - - for (unsigned i = 0; i + nlen <= buf.length; i++) - if (buf.arrayZ[i] == needle[0] && - !memcmp (buf.arrayZ + i, needle, nlen)) - return true; - return false; -} - -struct hb_svg_blob_meta_t -{ - char *data; - int allocated; - bool transferred; - bool in_replace; -}; - -static hb_user_data_key_t hb_svg_blob_meta_user_data_key; - -static void -hb_svg_blob_meta_set_buffer (hb_svg_blob_meta_t *meta, - char *data, - int allocated) -{ - meta->data = data; - meta->allocated = allocated; - meta->transferred = false; -} - -static void -hb_svg_blob_meta_release_buffer (hb_svg_blob_meta_t *meta) -{ - if (!meta) - return; - if (!meta->transferred && meta->data) - hb_free (meta->data); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_blob_meta_destroy (void *data) -{ - auto *meta = (hb_svg_blob_meta_t *) data; - hb_svg_blob_meta_release_buffer (meta); - if (meta->in_replace) - { - meta->in_replace = false; - return; - } - hb_free (meta); -} - -static hb_blob_t * -hb_svg_blob_from_buffer (hb_blob_t **recycled_blob, - hb_vector_t *buf) -{ - unsigned len = 0; - int allocated = 0; - char *data = buf->steal (&len, &allocated); - if (!data) - return nullptr; - - hb_blob_t *blob = nullptr; - if (*recycled_blob) - blob = *recycled_blob; - bool reused_blob = blob && blob != hb_blob_get_empty (); - bool new_meta = false; - auto *meta = reused_blob - ? (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key) - : nullptr; - if (!meta) - { - meta = (hb_svg_blob_meta_t *) hb_malloc (sizeof (hb_svg_blob_meta_t)); - if (!meta) - { - hb_free (data); - return nullptr; - } - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; - meta->in_replace = false; - new_meta = true; - } - - if (reused_blob) - { - /* replace_buffer() first destroys old buffer user_data; keep meta alive. */ - meta->in_replace = true; - blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - hb_svg_blob_meta_set_buffer (meta, data, allocated); - } - else - { - hb_svg_blob_meta_set_buffer (meta, data, allocated); - blob = hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - } - - if (unlikely (blob == hb_blob_get_empty ())) - { - if (new_meta) - hb_free (meta); - hb_free (data); - return nullptr; - } - - if (new_meta && - !hb_blob_set_user_data (blob, - &hb_svg_blob_meta_user_data_key, - meta, - nullptr, - true)) - { - if (!reused_blob) - hb_blob_destroy (blob); - return nullptr; - } - - if (*recycled_blob) - *recycled_blob = nullptr; - - return blob; -} - -static void -hb_svg_recover_recycled_buffer (hb_blob_t *blob, - hb_vector_t *buf) -{ - if (!blob) - return; - - auto *meta = (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key); - if (!meta || meta->transferred || !meta->data) - return; - - buf->recycle_buffer (meta->data, 0, meta->allocated); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -HB_UNUSED static void -hb_svg_append_color (hb_vector_t *buf, - hb_color_t color, - bool with_alpha) -{ - static const char hex[] = "0123456789ABCDEF"; - unsigned r = hb_color_get_red (color); - unsigned g = hb_color_get_green (color); - unsigned b = hb_color_get_blue (color); - unsigned a = hb_color_get_alpha (color); - hb_svg_append_c (buf, '#'); - if (((r >> 4) == (r & 0xF)) && - ((g >> 4) == (g & 0xF)) && - ((b >> 4) == (b & 0xF))) - { - hb_svg_append_c (buf, hex[r & 0xF]); - hb_svg_append_c (buf, hex[g & 0xF]); - hb_svg_append_c (buf, hex[b & 0xF]); - } - else - { - hb_svg_append_hex_byte (buf, r); - hb_svg_append_hex_byte (buf, g); - hb_svg_append_hex_byte (buf, b); - } - if (with_alpha && a != 255) - { - hb_svg_append_str (buf, "\" fill-opacity=\""); - hb_svg_append_num (buf, a / 255.f, 4); - } -} - -static void -hb_svg_transform_point (const hb_transform_t<> &t, - float x_scale_factor, - float y_scale_factor, - float x, float y, - float *tx, float *ty) -{ - float xx = x, yy = y; - t.transform_point (xx, yy); - *tx = xx / (x_scale_factor > 0 ? x_scale_factor : 1.f); - *ty = yy / (y_scale_factor > 0 ? y_scale_factor : 1.f); -} - -static hb_bool_t -hb_svg_set_glyph_extents_common (const hb_transform_t<> &transform, - float x_scale_factor, - float y_scale_factor, - const hb_glyph_extents_t *glyph_extents, - hb_vector_extents_t *extents, - hb_bool_t *has_extents) -{ - float x0 = (float) glyph_extents->x_bearing; - float y0 = (float) glyph_extents->y_bearing; - float x1 = x0 + glyph_extents->width; - float y1 = y0 + glyph_extents->height; - - float px[4] = {x0, x0, x1, x1}; - float py[4] = {y0, y1, y0, y1}; - - float tx, ty; - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty); - float tx_min = tx, tx_max = tx; - float ty_min = ty, ty_max = ty; - - for (unsigned i = 1; i < 4; i++) - { - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty); - tx_min = hb_min (tx_min, tx); - tx_max = hb_max (tx_max, tx); - ty_min = hb_min (ty_min, ty); - ty_max = hb_max (ty_max, ty); - } - - if (tx_max <= tx_min || ty_max <= ty_min) - { - return false; - } - - if (*has_extents) - { - float x0 = hb_min (extents->x, tx_min); - float y0 = hb_min (extents->y, ty_min); - float x1 = hb_max (extents->x + extents->width, tx_max); - float y1 = hb_max (extents->y + extents->height, ty_max); - *extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - *extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min}; - *has_extents = true; - } - return true; -} - - -struct hb_vector_draw_t -{ - hb_object_header_t header; - - hb_vector_format_t format = HB_VECTOR_FORMAT_SVG; - hb_transform_t<> transform = {1, 0, 0, 1, 0, 0}; - float x_scale_factor = 1.f; - float y_scale_factor = 1.f; - hb_vector_extents_t extents = {0, 0, 0, 0}; - bool has_extents = false; - unsigned precision = 2; - bool flat = false; - - hb_vector_t defs; - hb_vector_t body; - hb_vector_t path; - hb_set_t *defined_glyphs = nullptr; - hb_blob_t *recycled_blob = nullptr; - - void append_xy (float x, float y) - { - float tx, ty; - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, x, y, &tx, &ty); - hb_svg_append_num (&path, tx, precision); - hb_svg_append_c (&path, ','); - hb_svg_append_num (&path, ty, precision); - } -}; - -static inline void -hb_svg_append_instance_transform (hb_vector_t *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float xx, float yx, - float xy, float yy, - float tx, float ty) -{ - unsigned sprec = hb_svg_scale_precision (precision); - if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f) - { - float sx = 1.f / x_scale_factor; - float sy = 1.f / y_scale_factor; - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_str (out, ") scale("); - hb_svg_append_num (out, sx, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -sy, sprec, true); - hb_svg_append_c (out, ')'); - } - else - { - hb_svg_append_str (out, "matrix("); - hb_svg_append_num (out, xx / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, yx / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -xy / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -yy / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); - } -} - -HB_UNUSED static inline void -hb_svg_append_image_instance_translate (hb_vector_t *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float tx, float ty) -{ - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); -} - - -static void -hb_vector_draw_move_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float to_x, float to_y, - void *) -{ - auto *d = (hb_vector_draw_t *) draw_data; - hb_svg_append_c (&d->path, 'M'); - d->append_xy (to_x, to_y); -} - -static void -hb_vector_draw_line_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float to_x, float to_y, - void *) -{ - auto *d = (hb_vector_draw_t *) draw_data; - hb_svg_append_c (&d->path, 'L'); - d->append_xy (to_x, to_y); -} - -static void -hb_vector_draw_quadratic_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float cx, float cy, - float to_x, float to_y, - void *) -{ - auto *d = (hb_vector_draw_t *) draw_data; - hb_svg_append_c (&d->path, 'Q'); - d->append_xy (cx, cy); - hb_svg_append_c (&d->path, ' '); - d->append_xy (to_x, to_y); -} - -static void -hb_vector_draw_cubic_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float c1x, float c1y, - float c2x, float c2y, - float to_x, float to_y, - void *) -{ - auto *d = (hb_vector_draw_t *) draw_data; - hb_svg_append_c (&d->path, 'C'); - d->append_xy (c1x, c1y); - hb_svg_append_c (&d->path, ' '); - d->append_xy (c2x, c2y); - hb_svg_append_c (&d->path, ' '); - d->append_xy (to_x, to_y); -} - -static void -hb_vector_draw_close_path (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - void *) -{ - auto *d = (hb_vector_draw_t *) draw_data; - hb_svg_append_c (&d->path, 'Z'); -} - -static inline void free_static_vector_draw_funcs (); - -static struct hb_vector_draw_funcs_lazy_loader_t - : hb_draw_funcs_lazy_loader_t -{ - static hb_draw_funcs_t *create () - { - hb_draw_funcs_t *funcs = hb_draw_funcs_create (); - hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) hb_vector_draw_move_to, nullptr, nullptr); - hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) hb_vector_draw_line_to, nullptr, nullptr); - hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) hb_vector_draw_quadratic_to, nullptr, nullptr); - hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) hb_vector_draw_cubic_to, nullptr, nullptr); - hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) hb_vector_draw_close_path, nullptr, nullptr); - hb_draw_funcs_make_immutable (funcs); - hb_atexit (free_static_vector_draw_funcs); - return funcs; - } -} static_vector_draw_funcs; - -static inline void -free_static_vector_draw_funcs () -{ - static_vector_draw_funcs.free_instance (); -} - -static hb_draw_funcs_t * -hb_vector_draw_funcs_get () -{ - return static_vector_draw_funcs.get_unconst (); -} - -/** - * hb_vector_draw_create_or_fail: - * @format: output format. - * - * Creates a new draw context for vector output. - * - * Return value: (nullable): a newly allocated #hb_vector_draw_t, or `NULL` on failure. - * - * Since: 13.0.0 - */ -hb_vector_draw_t * -hb_vector_draw_create_or_fail (hb_vector_format_t format) -{ - if (format != HB_VECTOR_FORMAT_SVG) - return nullptr; - - hb_vector_draw_t *draw = hb_object_create (); - if (unlikely (!draw)) - return nullptr; - draw->format = format; - draw->defined_glyphs = hb_set_create (); - draw->defs.alloc (2048); - draw->body.alloc (8192); - draw->path.alloc (2048); - return draw; -} - -/** - * hb_vector_draw_reference: - * @draw: a draw context. - * - * Increases the reference count of @draw. - * - * Return value: (transfer full): referenced @draw. - * - * Since: 13.0.0 - */ -hb_vector_draw_t * -hb_vector_draw_reference (hb_vector_draw_t *draw) -{ - return hb_object_reference (draw); -} - -/** - * hb_vector_draw_destroy: - * @draw: a draw context. - * - * Decreases the reference count of @draw and destroys it when it reaches zero. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_destroy (hb_vector_draw_t *draw) -{ - if (!hb_object_destroy (draw)) return; - hb_blob_destroy (draw->recycled_blob); - hb_set_destroy (draw->defined_glyphs); - hb_free (draw); -} - -/** - * hb_vector_draw_set_user_data: - * @draw: a draw context. - * @key: user-data key. - * @data: user-data value. - * @destroy: (nullable): destroy callback for @data. - * @replace: whether to replace an existing value for @key. - * - * Attaches user data to @draw. - * - * Return value: `true` on success, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_draw_set_user_data (hb_vector_draw_t *draw, - hb_user_data_key_t *key, - void *data, - hb_destroy_func_t destroy, - hb_bool_t replace) -{ - return hb_object_set_user_data (draw, key, data, destroy, replace); -} - -/** - * hb_vector_draw_get_user_data: - * @draw: a draw context. - * @key: user-data key. - * - * Gets previously attached user data from @draw. - * - * Return value: (nullable): user-data value associated with @key. - * - * Since: 13.0.0 - */ -void * -hb_vector_draw_get_user_data (hb_vector_draw_t *draw, - hb_user_data_key_t *key) -{ - return hb_object_get_user_data (draw, key); -} - -/** - * hb_vector_draw_set_transform: - * @draw: a draw context. - * @xx: transform xx component. - * @yx: transform yx component. - * @xy: transform xy component. - * @yy: transform yy component. - * @dx: transform x translation. - * @dy: transform y translation. - * - * Sets the affine transform used when drawing glyphs. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_set_transform (hb_vector_draw_t *draw, - float xx, float yx, - float xy, float yy, - float dx, float dy) -{ - draw->transform = {xx, yx, xy, yy, dx, dy}; -} - -/** - * hb_vector_draw_get_transform: - * @draw: a draw context. - * @xx: (out) (nullable): transform xx component. - * @yx: (out) (nullable): transform yx component. - * @xy: (out) (nullable): transform xy component. - * @yy: (out) (nullable): transform yy component. - * @dx: (out) (nullable): transform x translation. - * @dy: (out) (nullable): transform y translation. - * - * Gets the affine transform used when drawing glyphs. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_get_transform (hb_vector_draw_t *draw, - float *xx, float *yx, - float *xy, float *yy, - float *dx, float *dy) -{ - if (xx) *xx = draw->transform.xx; - if (yx) *yx = draw->transform.yx; - if (xy) *xy = draw->transform.xy; - if (yy) *yy = draw->transform.yy; - if (dx) *dx = draw->transform.x0; - if (dy) *dy = draw->transform.y0; -} - -/** - * hb_vector_draw_set_scale_factor: - * @draw: a draw context. - * @x_scale_factor: x scale factor. - * @y_scale_factor: y scale factor. - * - * Sets additional output scaling factors. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_set_scale_factor (hb_vector_draw_t *draw, - float x_scale_factor, - float y_scale_factor) -{ - draw->x_scale_factor = x_scale_factor > 0.f ? x_scale_factor : 1.f; - draw->y_scale_factor = y_scale_factor > 0.f ? y_scale_factor : 1.f; -} - -/** - * hb_vector_draw_get_scale_factor: - * @draw: a draw context. - * @x_scale_factor: (out) (nullable): x scale factor. - * @y_scale_factor: (out) (nullable): y scale factor. - * - * Gets additional output scaling factors. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_get_scale_factor (hb_vector_draw_t *draw, - float *x_scale_factor, - float *y_scale_factor) -{ - if (x_scale_factor) *x_scale_factor = draw->x_scale_factor; - if (y_scale_factor) *y_scale_factor = draw->y_scale_factor; -} - -/** - * hb_vector_draw_set_extents: - * @draw: a draw context. - * @extents: (nullable): output extents to set or expand. - * - * Sets or expands output extents on @draw. Passing `NULL` clears extents. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_set_extents (hb_vector_draw_t *draw, - const hb_vector_extents_t *extents) -{ - if (!extents) - { - draw->extents = {0, 0, 0, 0}; - draw->has_extents = false; - return; - } - - if (!(extents->width > 0.f && extents->height > 0.f)) - return; - - if (draw->has_extents) - { - float x0 = hb_min (draw->extents.x, extents->x); - float y0 = hb_min (draw->extents.y, extents->y); - float x1 = hb_max (draw->extents.x + draw->extents.width, - extents->x + extents->width); - float y1 = hb_max (draw->extents.y + draw->extents.height, - extents->y + extents->height); - draw->extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - draw->extents = *extents; - draw->has_extents = true; - } -} - -/** - * hb_vector_draw_get_extents: - * @draw: a draw context. - * @extents: (out) (nullable): where to store current output extents. - * - * Gets current output extents from @draw. - * - * Return value: `true` if extents are set, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_draw_get_extents (hb_vector_draw_t *draw, - hb_vector_extents_t *extents) -{ - if (!draw->has_extents) - return false; - - if (extents) - *extents = draw->extents; - return true; -} - -/** - * hb_vector_draw_set_glyph_extents: - * @draw: a draw context. - * @glyph_extents: glyph extents in font units. - * - * Expands @draw extents using @glyph_extents under the current transform. - * - * Return value: `true` on success, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_draw_set_glyph_extents (hb_vector_draw_t *draw, - const hb_glyph_extents_t *glyph_extents) -{ - hb_bool_t has_extents = draw->has_extents; - hb_bool_t ret = hb_svg_set_glyph_extents_common (draw->transform, - draw->x_scale_factor, - draw->y_scale_factor, - glyph_extents, - &draw->extents, - &has_extents); - draw->has_extents = has_extents; - return ret; -} - -/** - * hb_vector_draw_get_funcs: - * - * Gets draw callbacks implemented by the vector draw backend. - * - * Return value: (transfer none): immutable #hb_draw_funcs_t singleton. - * - * Since: 13.0.0 - */ -hb_draw_funcs_t * -hb_vector_draw_get_funcs (void) -{ - return hb_vector_draw_funcs_get (); -} - -/** - * hb_vector_draw_glyph: - * @draw: a draw context. - * @font: font object. - * @glyph: glyph ID. - * @pen_x: glyph x origin before context transform. - * @pen_y: glyph y origin before context transform. - * @extents_mode: extents update mode. - * - * Draws one glyph into @draw. - * - * Return value: `true` if glyph data was emitted, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_draw_glyph (hb_vector_draw_t *draw, - hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y, - hb_vector_extents_mode_t extents_mode) -{ - if (draw->format != HB_VECTOR_FORMAT_SVG) - return false; - - if (extents_mode == HB_VECTOR_EXTENTS_MODE_EXPAND) - { - hb_glyph_extents_t ge; - if (hb_font_get_glyph_extents (font, glyph, &ge)) - { - float xx = draw->transform.xx; - float yx = draw->transform.yx; - float xy = draw->transform.xy; - float yy = draw->transform.yy; - float tx = draw->transform.x0 + xx * pen_x + xy * pen_y; - float ty = draw->transform.y0 + yx * pen_x + yy * pen_y; - hb_transform_t<> extents_transform = {xx, yx, -xy, -yy, tx, ty}; - - hb_bool_t has_extents = draw->has_extents; - hb_svg_set_glyph_extents_common (extents_transform, - draw->x_scale_factor, - draw->y_scale_factor, - &ge, - &draw->extents, - &has_extents); - draw->has_extents = has_extents; - } - } - - bool needs_def = !draw->flat && !hb_set_has (draw->defined_glyphs, glyph); - if (needs_def) - { - draw->path.clear (); - hb_svg_path_sink_t sink = {&draw->path, draw->precision}; - hb_font_draw_glyph (font, glyph, hb_svg_path_draw_funcs_get (), &sink); - if (!draw->path.length) - return false; - hb_svg_append_str (&draw->defs, "defs, glyph); - hb_svg_append_str (&draw->defs, "\" d=\""); - hb_svg_append_len (&draw->defs, draw->path.arrayZ, draw->path.length); - hb_svg_append_str (&draw->defs, "\"/>\n"); - hb_set_add (draw->defined_glyphs, glyph); - } - - if (draw->flat) - { - draw->path.clear (); - hb_svg_path_sink_t sink = {&draw->path, draw->precision}; - hb_font_draw_glyph (font, glyph, hb_svg_path_draw_funcs_get (), &sink); - - if (!draw->path.length) - return false; - - float xx = draw->transform.xx; - float yx = draw->transform.yx; - float xy = draw->transform.xy; - float yy = draw->transform.yy; - float tx = draw->transform.x0 + xx * pen_x + xy * pen_y; - float ty = draw->transform.y0 + yx * pen_x + yy * pen_y; - - hb_svg_append_str (&draw->body, "body, draw->path.arrayZ, draw->path.length); - hb_svg_append_str (&draw->body, "\" transform=\""); - hb_svg_append_instance_transform (&draw->body, - draw->precision, - draw->x_scale_factor, - draw->y_scale_factor, - xx, yx, xy, yy, tx, ty); - hb_svg_append_str (&draw->body, "\"/>\n"); - return true; - } - - float xx = draw->transform.xx; - float yx = draw->transform.yx; - float xy = draw->transform.xy; - float yy = draw->transform.yy; - float tx = draw->transform.x0 + xx * pen_x + xy * pen_y; - float ty = draw->transform.y0 + yx * pen_x + yy * pen_y; - - hb_svg_append_str (&draw->body, "body, glyph); - hb_svg_append_str (&draw->body, "\" transform=\""); - hb_svg_append_instance_transform (&draw->body, - draw->precision, - draw->x_scale_factor, - draw->y_scale_factor, - xx, yx, xy, yy, tx, ty); - hb_svg_append_str (&draw->body, "\"/>\n"); - return true; -} - -/** - * hb_vector_svg_set_flat: - * @draw: a draw context. - * @flat: whether to flatten geometry and disable reuse. - * - * Enables or disables SVG draw flattening. - * - * Since: 13.0.0 - */ -void -hb_vector_svg_set_flat (hb_vector_draw_t *draw, - hb_bool_t flat) -{ - draw->flat = !!flat; -} - -/** - * hb_vector_svg_set_precision: - * @draw: a draw context. - * @precision: decimal precision. - * - * Sets numeric output precision for SVG draw output. - * - * Since: 13.0.0 - */ -void -hb_vector_svg_set_precision (hb_vector_draw_t *draw, - unsigned precision) -{ - draw->precision = hb_min (precision, 12u); -} - -/** - * hb_vector_draw_render: - * @draw: a draw context. - * - * Renders accumulated draw content to an SVG blob. - * - * Return value: (transfer full) (nullable): output blob, or `NULL` if rendering cannot proceed. - * - * Since: 13.0.0 - */ -hb_blob_t * -hb_vector_draw_render (hb_vector_draw_t *draw) -{ - if (draw->format != HB_VECTOR_FORMAT_SVG) - return nullptr; - if (!draw->has_extents) - return nullptr; - - hb_vector_t out; - hb_svg_recover_recycled_buffer (draw->recycled_blob, &out); - unsigned estimated = draw->defs.length + - (draw->body.length ? draw->body.length : draw->path.length) + - 256; - out.alloc (estimated); - hb_svg_append_str (&out, "extents.x, draw->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, draw->extents.y, draw->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, draw->extents.width, draw->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, draw->extents.height, draw->precision); - hb_svg_append_str (&out, "\" width=\""); - hb_svg_append_num (&out, draw->extents.width, draw->precision); - hb_svg_append_str (&out, "\" height=\""); - hb_svg_append_num (&out, draw->extents.height, draw->precision); - hb_svg_append_str (&out, "\">\n"); - - if (draw->defs.length) - { - hb_svg_append_str (&out, "\n"); - hb_svg_append_len (&out, draw->defs.arrayZ, draw->defs.length); - hb_svg_append_str (&out, "\n"); - } - - if (draw->body.length) - { - hb_svg_append_len (&out, draw->body.arrayZ, draw->body.length); - } - else if (draw->path.length) - { - hb_svg_append_str (&out, "path.arrayZ, draw->path.length); - hb_svg_append_str (&out, "\"/>\n"); - } - - hb_svg_append_str (&out, "\n"); - - hb_blob_t *blob = hb_svg_blob_from_buffer (&draw->recycled_blob, &out); - - draw->path.clear (); - draw->defs.clear (); - draw->body.clear (); - hb_set_clear (draw->defined_glyphs); - draw->has_extents = false; - draw->extents = {0, 0, 0, 0}; - - return blob; -} - -/** - * hb_vector_draw_reset: - * @draw: a draw context. - * - * Resets @draw state and clears accumulated content. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_reset (hb_vector_draw_t *draw) -{ - draw->transform = {1, 0, 0, 1, 0, 0}; - draw->x_scale_factor = 1.f; - draw->y_scale_factor = 1.f; - draw->extents = {0, 0, 0, 0}; - draw->has_extents = false; - draw->precision = 2; - draw->flat = false; - draw->defs.clear (); - draw->body.clear (); - draw->path.clear (); - hb_set_clear (draw->defined_glyphs); -} - -/** - * hb_vector_draw_recycle_blob: - * @draw: a draw context. - * @blob: (nullable): previously rendered blob to recycle. - * - * Provides a blob for internal buffer reuse by later render calls. - * - * Since: 13.0.0 - */ -void -hb_vector_draw_recycle_blob (hb_vector_draw_t *draw, - hb_blob_t *blob) -{ - hb_blob_destroy (draw->recycled_blob); - draw->recycled_blob = nullptr; - if (!blob || blob == hb_blob_get_empty ()) - return; - draw->recycled_blob = blob; -} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-paint.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-paint.cc deleted file mode 100644 index 438710d96b..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-paint.cc +++ /dev/null @@ -1,2171 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-vector.h" -#include "hb-blob.hh" -#include "hb-geometry.hh" -#include "hb-machinery.hh" -#include "hb-map.hh" -#include "hb-vector-svg-path.hh" -#include "hb-vector-svg-subset.hh" -#include "hb-vector-svg-utils.hh" - -#include -#include -#include - - -static bool -hb_svg_append_str (hb_vector_t *buf, const char *s) -{ - return hb_svg_append_len (buf, s, (unsigned) strlen (s)); -} - -static bool -hb_svg_append_unsigned (hb_vector_t *buf, unsigned v) -{ - char tmp[10]; - unsigned n = 0; - do { - tmp[n++] = (char) ('0' + (v % 10)); - v /= 10; - } while (v); - - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + n)))) - return false; - - for (unsigned i = 0; i < n; i++) - buf->arrayZ[old_len + i] = tmp[n - 1 - i]; - return true; -} - -static bool -hb_svg_append_hex_byte (hb_vector_t *buf, unsigned v) -{ - static const char hex[] = "0123456789ABCDEF"; - char tmp[2] = {hex[(v >> 4) & 15], hex[v & 15]}; - return hb_svg_append_len (buf, tmp, 2); -} - -static bool -hb_svg_append_base64 (hb_vector_t *buf, - const uint8_t *data, - unsigned len) -{ - static const char b64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - unsigned out_len = ((len + 2) / 3) * 4; - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + out_len)))) - return false; - - char *dst = buf->arrayZ + old_len; - unsigned di = 0; - unsigned i = 0; - while (i + 2 < len) - { - unsigned v = ((unsigned) data[i] << 16) | - ((unsigned) data[i + 1] << 8) | - ((unsigned) data[i + 2]); - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = b64[(v >> 6) & 63]; - dst[di++] = b64[v & 63]; - i += 3; - } - - if (i < len) - { - unsigned v = (unsigned) data[i] << 16; - if (i + 1 < len) - v |= (unsigned) data[i + 1] << 8; - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = (i + 1 < len) ? b64[(v >> 6) & 63] : '='; - dst[di++] = '='; - } - - return true; -} - -struct hb_svg_blob_meta_t -{ - char *data; - int allocated; - bool transferred; - bool in_replace; -}; - -static hb_user_data_key_t hb_svg_blob_meta_user_data_key; - -static void -hb_svg_blob_meta_set_buffer (hb_svg_blob_meta_t *meta, - char *data, - int allocated) -{ - meta->data = data; - meta->allocated = allocated; - meta->transferred = false; -} - -static void -hb_svg_blob_meta_release_buffer (hb_svg_blob_meta_t *meta) -{ - if (!meta) - return; - if (!meta->transferred && meta->data) - hb_free (meta->data); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_blob_meta_destroy (void *data) -{ - auto *meta = (hb_svg_blob_meta_t *) data; - hb_svg_blob_meta_release_buffer (meta); - if (meta->in_replace) - { - meta->in_replace = false; - return; - } - hb_free (meta); -} - -static hb_blob_t * -hb_svg_blob_from_buffer (hb_blob_t **recycled_blob, - hb_vector_t *buf) -{ - unsigned len = 0; - int allocated = 0; - char *data = buf->steal (&len, &allocated); - if (!data) - return nullptr; - - hb_blob_t *blob = nullptr; - if (*recycled_blob) - blob = *recycled_blob; - bool reused_blob = blob && blob != hb_blob_get_empty (); - bool new_meta = false; - auto *meta = reused_blob - ? (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key) - : nullptr; - if (!meta) - { - meta = (hb_svg_blob_meta_t *) hb_malloc (sizeof (hb_svg_blob_meta_t)); - if (!meta) - { - hb_free (data); - return nullptr; - } - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; - meta->in_replace = false; - new_meta = true; - } - - if (reused_blob) - { - /* replace_buffer() first destroys old buffer user_data; keep meta alive. */ - meta->in_replace = true; - blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - hb_svg_blob_meta_set_buffer (meta, data, allocated); - } - else - { - hb_svg_blob_meta_set_buffer (meta, data, allocated); - blob = hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - } - - if (unlikely (blob == hb_blob_get_empty ())) - { - if (new_meta) - hb_free (meta); - hb_free (data); - return nullptr; - } - - if (new_meta && - !hb_blob_set_user_data (blob, - &hb_svg_blob_meta_user_data_key, - meta, - nullptr, - true)) - { - if (!reused_blob) - hb_blob_destroy (blob); - return nullptr; - } - - if (*recycled_blob) - *recycled_blob = nullptr; - - return blob; -} - -static void -hb_svg_recover_recycled_buffer (hb_blob_t *blob, - hb_vector_t *buf) -{ - if (!blob) - return; - - auto *meta = (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key); - if (!meta || meta->transferred || !meta->data) - return; - - buf->recycle_buffer (meta->data, 0, meta->allocated); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_append_color (hb_vector_t *buf, - hb_color_t color, - bool with_alpha) -{ - static const char hex[] = "0123456789ABCDEF"; - unsigned r = hb_color_get_red (color); - unsigned g = hb_color_get_green (color); - unsigned b = hb_color_get_blue (color); - unsigned a = hb_color_get_alpha (color); - hb_svg_append_c (buf, '#'); - if (((r >> 4) == (r & 0xF)) && - ((g >> 4) == (g & 0xF)) && - ((b >> 4) == (b & 0xF))) - { - hb_svg_append_c (buf, hex[r & 0xF]); - hb_svg_append_c (buf, hex[g & 0xF]); - hb_svg_append_c (buf, hex[b & 0xF]); - } - else - { - hb_svg_append_hex_byte (buf, r); - hb_svg_append_hex_byte (buf, g); - hb_svg_append_hex_byte (buf, b); - } - if (with_alpha && a != 255) - { - hb_svg_append_str (buf, "\" fill-opacity=\""); - hb_svg_append_num (buf, a / 255.f, 4); - } -} - -static void -hb_svg_transform_point (const hb_transform_t<> &t, - float x_scale_factor, - float y_scale_factor, - float x, float y, - float *tx, float *ty) -{ - float xx = x, yy = y; - t.transform_point (xx, yy); - *tx = xx / (x_scale_factor > 0 ? x_scale_factor : 1.f); - *ty = yy / (y_scale_factor > 0 ? y_scale_factor : 1.f); -} - -static hb_bool_t -hb_svg_set_glyph_extents_common (const hb_transform_t<> &transform, - float x_scale_factor, - float y_scale_factor, - const hb_glyph_extents_t *glyph_extents, - hb_vector_extents_t *extents, - hb_bool_t *has_extents) -{ - float x0 = (float) glyph_extents->x_bearing; - float y0 = (float) glyph_extents->y_bearing; - float x1 = x0 + glyph_extents->width; - float y1 = y0 + glyph_extents->height; - - float px[4] = {x0, x0, x1, x1}; - float py[4] = {y0, y1, y0, y1}; - - float tx, ty; - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty); - float tx_min = tx, tx_max = tx; - float ty_min = ty, ty_max = ty; - - for (unsigned i = 1; i < 4; i++) - { - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty); - tx_min = hb_min (tx_min, tx); - tx_max = hb_max (tx_max, tx); - ty_min = hb_min (ty_min, ty); - ty_max = hb_max (ty_max, ty); - } - - if (tx_max <= tx_min || ty_max <= ty_min) - { - return false; - } - - if (*has_extents) - { - float x0 = hb_min (extents->x, tx_min); - float y0 = hb_min (extents->y, ty_min); - float x1 = hb_max (extents->x + extents->width, tx_max); - float y1 = hb_max (extents->y + extents->height, ty_max); - *extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - *extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min}; - *has_extents = true; - } - return true; -} - - -struct hb_svg_color_glyph_cache_key_t -{ - hb_codepoint_t glyph = HB_CODEPOINT_INVALID; - unsigned palette = 0; - hb_color_t foreground = 0; - - hb_svg_color_glyph_cache_key_t () = default; - hb_svg_color_glyph_cache_key_t (hb_codepoint_t g, unsigned p, hb_color_t f) - : glyph (g), palette (p), foreground (f) {} - - bool operator == (const hb_svg_color_glyph_cache_key_t &o) const - { - return glyph == o.glyph && - palette == o.palette && - foreground == o.foreground; - } - - uint32_t hash () const - { - uint32_t h = hb_hash (glyph); - h = h * 31u + hb_hash (palette); - h = h * 31u + hb_hash (foreground); - return h; - } -}; - -struct hb_vector_paint_t -{ - hb_object_header_t header; - - hb_vector_format_t format = HB_VECTOR_FORMAT_SVG; - hb_transform_t<> transform = {1, 0, 0, 1, 0, 0}; - float x_scale_factor = 1.f; - float y_scale_factor = 1.f; - hb_vector_extents_t extents = {0, 0, 0, 0}; - bool has_extents = false; - - hb_color_t foreground = HB_COLOR (0, 0, 0, 255); - int palette = 0; - hb_hashmap_t custom_palette_colors; - unsigned precision = 2; - bool flat = false; - - hb_vector_t defs; - hb_vector_t path; - hb_vector_t> group_stack; - uint64_t transform_group_open_mask = 0; - unsigned transform_group_depth = 0; - unsigned transform_group_overflow_depth = 0; - - unsigned clip_rect_counter = 0; - unsigned gradient_counter = 0; - unsigned color_glyph_counter = 0; - hb_set_t *defined_outlines = nullptr; - hb_set_t *defined_clips = nullptr; - hb_hashmap_t defined_color_glyphs; - hb_vector_t color_stops_scratch; - hb_vector_t subset_body_scratch; - hb_vector_t captured_scratch; - hb_blob_t *recycled_blob = nullptr; - bool current_color_glyph_has_svg_image = false; - hb_codepoint_t current_svg_image_glyph = HB_CODEPOINT_INVALID; - hb_face_t *current_face = nullptr; - unsigned svg_image_counter = 0; - - hb_vector_t ¤t_body () { return group_stack.tail (); } - - void append_global_transform_prefix (hb_vector_t *buf) - { - if (transform.xx == 1.f && transform.yx == 0.f && - transform.xy == 0.f && transform.yy == 1.f && - transform.x0 == 0.f && transform.y0 == 0.f && - x_scale_factor == 1.f && y_scale_factor == 1.f) - return; - - unsigned sprec = hb_svg_scale_precision (precision); - hb_svg_append_str (buf, "\n"); - } - - void append_global_transform_suffix (hb_vector_t *buf) - { - if (transform.xx == 1.f && transform.yx == 0.f && - transform.xy == 0.f && transform.yy == 1.f && - transform.x0 == 0.f && transform.y0 == 0.f && - x_scale_factor == 1.f && y_scale_factor == 1.f) - return; - hb_svg_append_str (buf, "\n"); - } -}; - -static inline uint64_t -hb_svg_pack_color_glyph_cache_entry (unsigned def_id, - bool image_like) -{ - return ((uint64_t) def_id << 1) | (image_like ? 1ull : 0ull); -} - -static inline unsigned -hb_svg_cache_entry_def_id (uint64_t v) -{ - return (unsigned) (v >> 1); -} - -static inline bool -hb_svg_cache_entry_image_like (uint64_t v) -{ - return !!(v & 1ull); -} - -static inline hb_svg_color_glyph_cache_key_t -hb_svg_color_glyph_cache_key (hb_codepoint_t glyph, - unsigned palette, - hb_color_t foreground) -{ - return {glyph, palette, foreground}; -} - -static inline void -hb_svg_append_instance_transform (hb_vector_t *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float xx, float yx, - float xy, float yy, - float tx, float ty) -{ - unsigned sprec = hb_svg_scale_precision (precision); - if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f) - { - float sx = 1.f / x_scale_factor; - float sy = 1.f / y_scale_factor; - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_str (out, ") scale("); - hb_svg_append_num (out, sx, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -sy, sprec, true); - hb_svg_append_c (out, ')'); - } - else - { - hb_svg_append_str (out, "matrix("); - hb_svg_append_num (out, xx / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, yx / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -xy / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -yy / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); - } -} - -static inline void -hb_svg_append_image_instance_translate (hb_vector_t *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float tx, float ty) -{ - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); -} - -static hb_bool_t -hb_svg_get_color_stops (hb_vector_paint_t *paint, - hb_color_line_t *color_line, - hb_vector_t *stops) -{ - unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); - if (unlikely (!stops->resize (len))) - return false; - hb_color_line_get_color_stops (color_line, 0, &len, stops->arrayZ); - - for (unsigned i = 0; i < len; i++) - if (stops->arrayZ[i].is_foreground) - stops->arrayZ[i].color = HB_COLOR (hb_color_get_blue (paint->foreground), - hb_color_get_green (paint->foreground), - hb_color_get_red (paint->foreground), - (unsigned) hb_color_get_alpha (stops->arrayZ[i].color) * - hb_color_get_alpha (paint->foreground) / 255); - return true; -} - -static const char * -hb_svg_extend_mode_str (hb_paint_extend_t ext) -{ - switch (ext) - { - case HB_PAINT_EXTEND_PAD: return "pad"; - case HB_PAINT_EXTEND_REPEAT: return "repeat"; - case HB_PAINT_EXTEND_REFLECT: return "reflect"; - default: return "pad"; - } -} - -static int -hb_svg_color_stop_cmp (const void *a, const void *b) -{ - const hb_color_stop_t *x = (const hb_color_stop_t *) a; - const hb_color_stop_t *y = (const hb_color_stop_t *) b; - if (x->offset < y->offset) return -1; - if (x->offset > y->offset) return 1; - return 0; -} - -static void -hb_svg_emit_color_stops (hb_vector_paint_t *paint, - hb_vector_t *buf, - hb_vector_t *stops) -{ - for (unsigned i = 0; i < stops->length; i++) - { - hb_color_t c = stops->arrayZ[i].color; - hb_svg_append_str (buf, "arrayZ[i].offset, 4); - hb_svg_append_str (buf, "\" stop-color=\"rgb("); - hb_svg_append_unsigned (buf, hb_color_get_red (c)); - hb_svg_append_c (buf, ','); - hb_svg_append_unsigned (buf, hb_color_get_green (c)); - hb_svg_append_c (buf, ','); - hb_svg_append_unsigned (buf, hb_color_get_blue (c)); - hb_svg_append_str (buf, ")\""); - if (hb_color_get_alpha (c) != 255) - { - hb_svg_append_str (buf, " stop-opacity=\""); - hb_svg_append_num (buf, hb_color_get_alpha (c) / 255.f, 4); - hb_svg_append_c (buf, '"'); - } - hb_svg_append_str (buf, "/>\n"); - } -} - -static const char * -hb_svg_composite_mode_str (hb_paint_composite_mode_t mode) -{ - switch (mode) - { - case HB_PAINT_COMPOSITE_MODE_CLEAR: - case HB_PAINT_COMPOSITE_MODE_SRC: - case HB_PAINT_COMPOSITE_MODE_DEST: - case HB_PAINT_COMPOSITE_MODE_DEST_OVER: - case HB_PAINT_COMPOSITE_MODE_SRC_IN: - case HB_PAINT_COMPOSITE_MODE_DEST_IN: - case HB_PAINT_COMPOSITE_MODE_SRC_OUT: - case HB_PAINT_COMPOSITE_MODE_DEST_OUT: - case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: - case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: - case HB_PAINT_COMPOSITE_MODE_XOR: - case HB_PAINT_COMPOSITE_MODE_PLUS: - return nullptr; - case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return "normal"; - case HB_PAINT_COMPOSITE_MODE_SCREEN: return "screen"; - case HB_PAINT_COMPOSITE_MODE_OVERLAY: return "overlay"; - case HB_PAINT_COMPOSITE_MODE_DARKEN: return "darken"; - case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return "lighten"; - case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return "color-dodge"; - case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return "color-burn"; - case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return "hard-light"; - case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return "soft-light"; - case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return "difference"; - case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return "exclusion"; - case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return "multiply"; - case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return "hue"; - case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return "saturation"; - case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return "color"; - case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return "luminosity"; - default: return nullptr; - } -} - -struct hb_svg_point_t { float x, y; }; -struct hb_svg_rgba_t { float r, g, b, a; }; - -static inline float -hb_svg_lerp (float a, float b, float t) -{ return a + (b - a) * t; } - -static inline float -hb_svg_clamp01 (float v) -{ - if (v < 0.f) return 0.f; - if (v > 1.f) return 1.f; - return v; -} - -static inline hb_svg_rgba_t -hb_svg_rgba_from_hb_color (hb_color_t c) -{ - return {(float) hb_color_get_red (c) / 255.f, - (float) hb_color_get_green (c) / 255.f, - (float) hb_color_get_blue (c) / 255.f, - (float) hb_color_get_alpha (c) / 255.f}; -} - -static inline hb_color_t -hb_svg_hb_color_from_rgba (const hb_svg_rgba_t &c) -{ - unsigned r = (unsigned) roundf (hb_svg_clamp01 (c.r) * 255.f); - unsigned g = (unsigned) roundf (hb_svg_clamp01 (c.g) * 255.f); - unsigned b = (unsigned) roundf (hb_svg_clamp01 (c.b) * 255.f); - unsigned a = (unsigned) roundf (hb_svg_clamp01 (c.a) * 255.f); - return HB_COLOR (b, g, r, a); -} - -static inline hb_svg_rgba_t -hb_svg_lerp_rgba (const hb_svg_rgba_t &c0, - const hb_svg_rgba_t &c1, - float t) -{ - return {hb_svg_lerp (c0.r, c1.r, t), - hb_svg_lerp (c0.g, c1.g, t), - hb_svg_lerp (c0.b, c1.b, t), - hb_svg_lerp (c0.a, c1.a, t)}; -} - -static inline float hb_svg_dot (const hb_svg_point_t &p, const hb_svg_point_t &q) { return p.x * q.x + p.y * q.y; } -static inline hb_svg_point_t hb_svg_add (const hb_svg_point_t &p, const hb_svg_point_t &q) { return {p.x + q.x, p.y + q.y}; } -static inline hb_svg_point_t hb_svg_sub (const hb_svg_point_t &p, const hb_svg_point_t &q) { return {p.x - q.x, p.y - q.y}; } -static inline hb_svg_point_t hb_svg_scale (const hb_svg_point_t &p, float f) { return {p.x * f, p.y * f}; } - -static inline hb_svg_point_t -hb_svg_normalize (const hb_svg_point_t &p) -{ - float len = sqrtf (hb_svg_dot (p, p)); - if (len == 0.f) return {0.f, 0.f}; - return hb_svg_scale (p, 1.f / len); -} - -static void -hb_svg_add_sweep_patch (hb_vector_t *body, - unsigned precision, - float cx, float cy, float radius, - float a0, const hb_svg_rgba_t &c0_in, - float a1, const hb_svg_rgba_t &c1_in) -{ - static const float max_angle = HB_PI / 16.f; - hb_svg_point_t center = {cx, cy}; - int num_splits = (int) ceilf (fabsf (a1 - a0) / max_angle); - if (num_splits < 1) num_splits = 1; - - hb_svg_point_t p0 = {cosf (a0), sinf (a0)}; - hb_svg_rgba_t color0 = c0_in; - - for (int a = 0; a < num_splits; a++) - { - float k = (a + 1.f) / num_splits; - float angle1 = hb_svg_lerp (a0, a1, k); - hb_svg_rgba_t color1 = hb_svg_lerp_rgba (c0_in, c1_in, k); - - hb_svg_point_t p1 = {cosf (angle1), sinf (angle1)}; - hb_svg_point_t sp0 = hb_svg_add (center, hb_svg_scale (p0, radius)); - hb_svg_point_t sp1 = hb_svg_add (center, hb_svg_scale (p1, radius)); - - hb_svg_point_t A = hb_svg_normalize (hb_svg_add (p0, p1)); - hb_svg_point_t U = {-A.y, A.x}; - float up0 = hb_svg_dot (U, p0); - float up1 = hb_svg_dot (U, p1); - if (fabsf (up0) < 1e-6f || fabsf (up1) < 1e-6f) - { - p0 = p1; - color0 = color1; - continue; - } - hb_svg_point_t C0 = hb_svg_add (A, hb_svg_scale (U, hb_svg_dot (hb_svg_sub (p0, A), p0) / up0)); - hb_svg_point_t C1 = hb_svg_add (A, hb_svg_scale (U, hb_svg_dot (hb_svg_sub (p1, A), p1) / up1)); - - hb_svg_point_t sc0 = hb_svg_add (center, hb_svg_scale (hb_svg_add (C0, hb_svg_scale (hb_svg_sub (C0, p0), 0.33333f)), radius)); - hb_svg_point_t sc1 = hb_svg_add (center, hb_svg_scale (hb_svg_add (C1, hb_svg_scale (hb_svg_sub (C1, p1), 0.33333f)), radius)); - - hb_svg_rgba_t mid_color = hb_svg_lerp_rgba (color0, color1, 0.5f); - hb_color_t mid = hb_svg_hb_color_from_rgba (mid_color); - - hb_svg_append_str (body, "\n"); - - p0 = p1; - color0 = color1; - } -} - -static void -hb_svg_add_sweep_gradient_patches (hb_vector_t *body, - unsigned precision, - hb_color_stop_t *stops, - unsigned n_stops, - hb_paint_extend_t extend, - float cx, float cy, float radius, - float start_angle, float end_angle) -{ - if (!n_stops) return; - - hb_svg_rgba_t colors_buf[16]; - float angles_buf[16]; - hb_svg_rgba_t *colors = colors_buf; - float *angles = angles_buf; - bool dynamic = false; - - if (start_angle == end_angle) - { - if (extend == HB_PAINT_EXTEND_PAD) - { - if (start_angle > 0.f) - { - hb_svg_rgba_t c = hb_svg_rgba_from_hb_color (stops[0].color); - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, 0.f, c, start_angle, c); - } - if (end_angle < HB_2_PI) - { - hb_svg_rgba_t c = hb_svg_rgba_from_hb_color (stops[n_stops - 1].color); - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, end_angle, c, HB_2_PI, c); - } - } - return; - } - - if (end_angle < start_angle) - { - float tmp = start_angle; start_angle = end_angle; end_angle = tmp; - for (unsigned i = 0; i < n_stops - 1 - i; i++) - { - hb_color_stop_t t = stops[i]; - stops[i] = stops[n_stops - 1 - i]; - stops[n_stops - 1 - i] = t; - } - for (unsigned i = 0; i < n_stops; i++) - stops[i].offset = 1.f - stops[i].offset; - } - - if (n_stops > 16) - { - angles = (float *) hb_malloc (sizeof (float) * n_stops); - colors = (hb_svg_rgba_t *) hb_malloc (sizeof (hb_svg_rgba_t) * n_stops); - if (!angles || !colors) - { - hb_free (angles); - hb_free (colors); - return; - } - dynamic = true; - } - - for (unsigned i = 0; i < n_stops; i++) - { - angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); - colors[i] = hb_svg_rgba_from_hb_color (stops[i].color); - } - - if (extend == HB_PAINT_EXTEND_PAD) - { - unsigned pos; - hb_svg_rgba_t color0 = colors[0]; - for (pos = 0; pos < n_stops; pos++) - { - if (angles[pos] >= 0) - { - if (pos > 0) - { - float f = (0.f - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); - color0 = hb_svg_lerp_rgba (colors[pos - 1], colors[pos], f); - } - break; - } - } - if (pos == n_stops) - { - color0 = colors[n_stops - 1]; - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, 0.f, color0, HB_2_PI, color0); - goto done; - } - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, 0.f, color0, angles[pos], colors[pos]); - for (pos++; pos < n_stops; pos++) - { - if (angles[pos] <= HB_2_PI) - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, angles[pos - 1], colors[pos - 1], angles[pos], colors[pos]); - else - { - float f = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); - hb_svg_rgba_t color1 = hb_svg_lerp_rgba (colors[pos - 1], colors[pos], f); - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, angles[pos - 1], colors[pos - 1], HB_2_PI, color1); - break; - } - } - if (pos == n_stops) - { - color0 = colors[n_stops - 1]; - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, angles[n_stops - 1], color0, HB_2_PI, color0); - goto done; - } - } - else - { - float span = angles[n_stops - 1] - angles[0]; - if (fabsf (span) < 1e-6f) - goto done; - - int k = 0; - if (angles[0] >= 0) - { - float ss = angles[0]; - while (ss > 0) - { - if (span > 0) { ss -= span; k--; } - else { ss += span; k++; } - } - } - else - { - float ee = angles[n_stops - 1]; - while (ee < 0) - { - if (span > 0) { ee += span; k++; } - else { ee -= span; k--; } - } - } - - span = fabsf (span); - for (int l = k; l < 1000; l++) - { - for (unsigned i = 1; i < n_stops; i++) - { - float a0_l, a1_l; - const hb_svg_rgba_t *col0, *col1; - if ((l % 2 != 0) && (extend == HB_PAINT_EXTEND_REFLECT)) - { - a0_l = angles[0] + angles[n_stops - 1] - angles[n_stops - i] + l * span; - a1_l = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; - col0 = &colors[n_stops - i]; - col1 = &colors[n_stops - 1 - i]; - } - else - { - a0_l = angles[i - 1] + l * span; - a1_l = angles[i] + l * span; - col0 = &colors[i - 1]; - col1 = &colors[i]; - } - - if (a1_l < 0.f) continue; - if (a0_l < 0.f) - { - float f = (0.f - a0_l) / (a1_l - a0_l); - hb_svg_rgba_t c = hb_svg_lerp_rgba (*col0, *col1, f); - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, 0.f, c, a1_l, *col1); - } - else if (a1_l >= HB_2_PI) - { - float f = (HB_2_PI - a0_l) / (a1_l - a0_l); - hb_svg_rgba_t c = hb_svg_lerp_rgba (*col0, *col1, f); - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, a0_l, *col0, HB_2_PI, c); - goto done; - } - else - hb_svg_add_sweep_patch (body, precision, cx, cy, radius, a0_l, *col0, a1_l, *col1); - } - } - } - -done: - if (dynamic) - { - hb_free (angles); - hb_free (colors); - } -} - - -static void hb_vector_paint_push_transform (hb_paint_funcs_t *, void *, - float, float, float, float, float, float, - void *); -static void hb_vector_paint_pop_transform (hb_paint_funcs_t *, void *, void *); -static void hb_vector_paint_push_clip_glyph (hb_paint_funcs_t *, void *, hb_codepoint_t, hb_font_t *, void *); -static void hb_vector_paint_push_clip_rectangle (hb_paint_funcs_t *, void *, float, float, float, float, void *); -static void hb_vector_paint_pop_clip (hb_paint_funcs_t *, void *, void *); -static void hb_vector_paint_color (hb_paint_funcs_t *, void *, hb_bool_t, hb_color_t, void *); -static hb_bool_t hb_vector_paint_image (hb_paint_funcs_t *, void *, hb_blob_t *, unsigned, unsigned, hb_tag_t, float, hb_glyph_extents_t *, void *); -static void hb_vector_paint_linear_gradient (hb_paint_funcs_t *, void *, hb_color_line_t *, float, float, float, float, float, float, void *); -static void hb_vector_paint_radial_gradient (hb_paint_funcs_t *, void *, hb_color_line_t *, float, float, float, float, float, float, void *); -static void hb_vector_paint_sweep_gradient (hb_paint_funcs_t *, void *, hb_color_line_t *, float, float, float, float, void *); -static void hb_vector_paint_push_group (hb_paint_funcs_t *, void *, void *); -static void hb_vector_paint_pop_group (hb_paint_funcs_t *, void *, hb_paint_composite_mode_t, void *); -static hb_bool_t hb_vector_paint_color_glyph (hb_paint_funcs_t *, void *, hb_codepoint_t, hb_font_t *, void *); -static hb_bool_t hb_vector_paint_custom_palette_color (hb_paint_funcs_t *, void *, unsigned, hb_color_t *, void *); - -static inline void free_static_vector_paint_funcs (); -static struct hb_vector_paint_funcs_lazy_loader_t - : hb_paint_funcs_lazy_loader_t -{ - static hb_paint_funcs_t *create () - { - hb_paint_funcs_t *funcs = hb_paint_funcs_create (); - hb_paint_funcs_set_push_transform_func (funcs, (hb_paint_push_transform_func_t) hb_vector_paint_push_transform, nullptr, nullptr); - hb_paint_funcs_set_pop_transform_func (funcs, (hb_paint_pop_transform_func_t) hb_vector_paint_pop_transform, nullptr, nullptr); - hb_paint_funcs_set_push_clip_glyph_func (funcs, (hb_paint_push_clip_glyph_func_t) hb_vector_paint_push_clip_glyph, nullptr, nullptr); - hb_paint_funcs_set_push_clip_rectangle_func (funcs, (hb_paint_push_clip_rectangle_func_t) hb_vector_paint_push_clip_rectangle, nullptr, nullptr); - hb_paint_funcs_set_pop_clip_func (funcs, (hb_paint_pop_clip_func_t) hb_vector_paint_pop_clip, nullptr, nullptr); - hb_paint_funcs_set_color_func (funcs, (hb_paint_color_func_t) hb_vector_paint_color, nullptr, nullptr); - hb_paint_funcs_set_image_func (funcs, (hb_paint_image_func_t) hb_vector_paint_image, nullptr, nullptr); - hb_paint_funcs_set_linear_gradient_func (funcs, (hb_paint_linear_gradient_func_t) hb_vector_paint_linear_gradient, nullptr, nullptr); - hb_paint_funcs_set_radial_gradient_func (funcs, (hb_paint_radial_gradient_func_t) hb_vector_paint_radial_gradient, nullptr, nullptr); - hb_paint_funcs_set_sweep_gradient_func (funcs, (hb_paint_sweep_gradient_func_t) hb_vector_paint_sweep_gradient, nullptr, nullptr); - hb_paint_funcs_set_push_group_func (funcs, (hb_paint_push_group_func_t) hb_vector_paint_push_group, nullptr, nullptr); - hb_paint_funcs_set_pop_group_func (funcs, (hb_paint_pop_group_func_t) hb_vector_paint_pop_group, nullptr, nullptr); - hb_paint_funcs_set_color_glyph_func (funcs, (hb_paint_color_glyph_func_t) hb_vector_paint_color_glyph, nullptr, nullptr); - hb_paint_funcs_set_custom_palette_color_func (funcs, (hb_paint_custom_palette_color_func_t) hb_vector_paint_custom_palette_color, nullptr, nullptr); - hb_paint_funcs_make_immutable (funcs); - hb_atexit (free_static_vector_paint_funcs); - return funcs; - } -} static_vector_paint_funcs; - -static inline void -free_static_vector_paint_funcs () -{ - static_vector_paint_funcs.free_instance (); -} - -static hb_paint_funcs_t * -hb_vector_paint_funcs_get () -{ - return static_vector_paint_funcs.get_unconst (); -} - -static void -hb_vector_paint_ensure_initialized (hb_vector_paint_t *paint) -{ - if (paint->group_stack.length) - return; - auto *root = paint->group_stack.push (); - if (likely (root)) - root->alloc (4096); -} - -static void -hb_vector_paint_push_transform (hb_paint_funcs_t *, - void *paint_data, - float xx, float yx, - float xy, float yy, - float dx, float dy, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - if (unlikely (paint->transform_group_overflow_depth)) - { - paint->transform_group_overflow_depth++; - return; - } - if (unlikely (paint->transform_group_depth >= 64)) - { - paint->transform_group_overflow_depth = 1; - return; - } - - hb_bool_t opened = - !(fabsf (xx - 1.f) < 1e-6f && fabsf (yx) < 1e-6f && - fabsf (xy) < 1e-6f && fabsf (yy - 1.f) < 1e-6f && - fabsf (dx) < 1e-6f && fabsf (dy) < 1e-6f); - paint->transform_group_open_mask = (paint->transform_group_open_mask << 1) | (opened ? 1ull : 0ull); - paint->transform_group_depth++; - - if (!opened) - return; - - auto &body = paint->current_body (); - unsigned sprec = hb_svg_scale_precision (paint->precision); - hb_svg_append_str (&body, "precision); - hb_svg_append_c (&body, ','); - hb_svg_append_num (&body, dy, paint->precision); - hb_svg_append_str (&body, ")\">\n"); -} - -static void -hb_vector_paint_pop_transform (hb_paint_funcs_t *, - void *paint_data, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - if (unlikely (paint->transform_group_overflow_depth)) - { - paint->transform_group_overflow_depth--; - return; - } - if (!paint->transform_group_depth) - return; - paint->transform_group_depth--; - hb_bool_t opened = !!(paint->transform_group_open_mask & 1ull); - paint->transform_group_open_mask >>= 1; - if (opened) - hb_svg_append_str (&paint->current_body (), "\n"); -} - -static void -hb_vector_paint_push_clip_glyph (hb_paint_funcs_t *, - void *paint_data, - hb_codepoint_t glyph, - hb_font_t *font, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - if (!hb_set_has (paint->defined_outlines, glyph)) - { - hb_set_add (paint->defined_outlines, glyph); - paint->path.clear (); - hb_svg_path_sink_t sink = {&paint->path, paint->precision}; - hb_font_draw_glyph (font, glyph, hb_svg_path_draw_funcs_get (), &sink); - hb_svg_append_str (&paint->defs, "defs, glyph); - hb_svg_append_str (&paint->defs, "\" d=\""); - hb_svg_append_len (&paint->defs, paint->path.arrayZ, paint->path.length); - hb_svg_append_str (&paint->defs, "\"/>\n"); - } - - if (!hb_set_has (paint->defined_clips, glyph)) - { - hb_set_add (paint->defined_clips, glyph); - hb_svg_append_str (&paint->defs, "defs, glyph); - hb_svg_append_str (&paint->defs, "\">defs, glyph); - hb_svg_append_str (&paint->defs, "\"/>\n"); - } - - hb_svg_append_str (&paint->current_body (), "current_body (), glyph); - hb_svg_append_str (&paint->current_body (), ")\">\n"); -} - -static void -hb_vector_paint_push_clip_rectangle (hb_paint_funcs_t *, - void *paint_data, - float xmin, float ymin, - float xmax, float ymax, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - unsigned clip_id = paint->clip_rect_counter++; - hb_svg_append_str (&paint->defs, "defs, clip_id); - hb_svg_append_str (&paint->defs, "\">defs, xmin, paint->precision); - hb_svg_append_str (&paint->defs, "\" y=\""); - hb_svg_append_num (&paint->defs, ymin, paint->precision); - hb_svg_append_str (&paint->defs, "\" width=\""); - hb_svg_append_num (&paint->defs, xmax - xmin, paint->precision); - hb_svg_append_str (&paint->defs, "\" height=\""); - hb_svg_append_num (&paint->defs, ymax - ymin, paint->precision); - hb_svg_append_str (&paint->defs, "\"/>\n"); - - hb_svg_append_str (&paint->current_body (), "current_body (), clip_id); - hb_svg_append_str (&paint->current_body (), ")\">\n"); -} - -static void -hb_vector_paint_pop_clip (hb_paint_funcs_t *, - void *paint_data, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - hb_svg_append_str (&paint->current_body (), "\n"); -} - -static void -hb_vector_paint_color (hb_paint_funcs_t *, - void *paint_data, - hb_bool_t is_foreground, - hb_color_t color, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - hb_color_t c = color; - if (is_foreground) - c = HB_COLOR (hb_color_get_blue (paint->foreground), - hb_color_get_green (paint->foreground), - hb_color_get_red (paint->foreground), - (unsigned) hb_color_get_alpha (paint->foreground) * hb_color_get_alpha (color) / 255); - - auto &body = paint->current_body (); - hb_svg_append_str (&body, "\n"); -} - -static hb_bool_t -hb_vector_paint_image (hb_paint_funcs_t *, - void *paint_data, - hb_blob_t *image, - unsigned width, - unsigned height, - hb_tag_t format, - float slant HB_UNUSED, - hb_glyph_extents_t *extents, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - auto &body = paint->current_body (); - if (format == HB_TAG ('s','v','g',' ')) - { - paint->current_color_glyph_has_svg_image = true; - - paint->subset_body_scratch.clear (); - bool subset_ok = hb_svg_subset_glyph_image (paint->current_face, - image, - paint->current_svg_image_glyph, - &paint->svg_image_counter, - &paint->defs, - &paint->subset_body_scratch); - if (unlikely (!subset_ok)) - return false; - - if (extents) - { - hb_svg_append_str (&body, "x_bearing, paint->precision); - hb_svg_append_c (&body, ','); - hb_svg_append_num (&body, (float) extents->y_bearing, paint->precision); - hb_svg_append_str (&body, ") scale("); - hb_svg_append_num (&body, (float) extents->width / width, paint->precision); - hb_svg_append_c (&body, ','); - hb_svg_append_num (&body, (float) extents->height / height, paint->precision); - hb_svg_append_str (&body, ")\">\n"); - } - - hb_svg_append_len (&body, - paint->subset_body_scratch.arrayZ, - paint->subset_body_scratch.length); - hb_svg_append_c (&body, '\n'); - - if (extents) - hb_svg_append_str (&body, "\n"); - - return true; - } - - if (format == HB_TAG ('p','n','g',' ')) - { - if (!extents || !width || !height) - return false; - - unsigned len = 0; - const char *png_data = hb_blob_get_data (image, &len); - if (!png_data || !len) - return false; - - hb_svg_append_str (&body, "x_bearing, paint->precision); - hb_svg_append_c (&body, ','); - hb_svg_append_num (&body, (float) extents->y_bearing, paint->precision); - hb_svg_append_str (&body, ") scale("); - hb_svg_append_num (&body, (float) extents->width / width, paint->precision); - hb_svg_append_c (&body, ','); - hb_svg_append_num (&body, (float) extents->height / height, paint->precision); - hb_svg_append_str (&body, ")\">\n"); - - hb_svg_append_str (&body, "precision); - hb_svg_append_str (&body, "\" height=\""); - hb_svg_append_num (&body, (float) height, paint->precision); - hb_svg_append_str (&body, "\"/>\n\n"); - - return true; - } - - return false; -} - -static void -hb_vector_paint_linear_gradient (hb_paint_funcs_t *, - void *paint_data, - hb_color_line_t *color_line, - float x0, float y0, - float x1, float y1, - float x2, float y2, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - hb_vector_t &stops = paint->color_stops_scratch; - if (!hb_svg_get_color_stops (paint, color_line, &stops) || !stops.length) - return; - - qsort (stops.arrayZ, stops.length, sizeof (hb_color_stop_t), hb_svg_color_stop_cmp); - - unsigned grad_id = paint->gradient_counter++; - - hb_svg_append_str (&paint->defs, "defs, grad_id); - hb_svg_append_str (&paint->defs, "\" gradientUnits=\"userSpaceOnUse\" x1=\""); - hb_svg_append_num (&paint->defs, x0, paint->precision); - hb_svg_append_str (&paint->defs, "\" y1=\""); - hb_svg_append_num (&paint->defs, y0, paint->precision); - hb_svg_append_str (&paint->defs, "\" x2=\""); - hb_svg_append_num (&paint->defs, x1 + (x1 - x2), paint->precision); - hb_svg_append_str (&paint->defs, "\" y2=\""); - hb_svg_append_num (&paint->defs, y1 + (y1 - y2), paint->precision); - hb_svg_append_str (&paint->defs, "\" spreadMethod=\""); - hb_svg_append_str (&paint->defs, hb_svg_extend_mode_str (hb_color_line_get_extend (color_line))); - hb_svg_append_str (&paint->defs, "\">\n"); - hb_svg_emit_color_stops (paint, &paint->defs, &stops); - hb_svg_append_str (&paint->defs, "\n"); - - hb_svg_append_str (&paint->current_body (), - "current_body (), grad_id); - hb_svg_append_str (&paint->current_body (), ")\"/>\n"); -} - -static void -hb_vector_paint_radial_gradient (hb_paint_funcs_t *, - void *paint_data, - hb_color_line_t *color_line, - float x0, float y0, float r0, - float x1, float y1, float r1, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - hb_vector_t &stops = paint->color_stops_scratch; - if (!hb_svg_get_color_stops (paint, color_line, &stops) || !stops.length) - return; - - qsort (stops.arrayZ, stops.length, sizeof (hb_color_stop_t), hb_svg_color_stop_cmp); - - unsigned grad_id = paint->gradient_counter++; - - hb_svg_append_str (&paint->defs, "defs, grad_id); - hb_svg_append_str (&paint->defs, "\" gradientUnits=\"userSpaceOnUse\" cx=\""); - hb_svg_append_num (&paint->defs, x1, paint->precision); - hb_svg_append_str (&paint->defs, "\" cy=\""); - hb_svg_append_num (&paint->defs, y1, paint->precision); - hb_svg_append_str (&paint->defs, "\" r=\""); - hb_svg_append_num (&paint->defs, r1, paint->precision); - hb_svg_append_str (&paint->defs, "\" fx=\""); - hb_svg_append_num (&paint->defs, x0, paint->precision); - hb_svg_append_str (&paint->defs, "\" fy=\""); - hb_svg_append_num (&paint->defs, y0, paint->precision); - if (r0 > 0) - { - hb_svg_append_str (&paint->defs, "\" fr=\""); - hb_svg_append_num (&paint->defs, r0, paint->precision); - } - hb_svg_append_str (&paint->defs, "\" spreadMethod=\""); - hb_svg_append_str (&paint->defs, hb_svg_extend_mode_str (hb_color_line_get_extend (color_line))); - hb_svg_append_str (&paint->defs, "\">\n"); - hb_svg_emit_color_stops (paint, &paint->defs, &stops); - hb_svg_append_str (&paint->defs, "\n"); - - hb_svg_append_str (&paint->current_body (), - "current_body (), grad_id); - hb_svg_append_str (&paint->current_body (), ")\"/>\n"); -} - -static void -hb_vector_paint_sweep_gradient (hb_paint_funcs_t *, - void *paint_data, - hb_color_line_t *color_line, - float cx, float cy, - float start_angle, float end_angle, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - - hb_vector_t &stops = paint->color_stops_scratch; - if (!hb_svg_get_color_stops (paint, color_line, &stops) || !stops.length) - return; - - qsort (stops.arrayZ, stops.length, sizeof (hb_color_stop_t), hb_svg_color_stop_cmp); - hb_svg_add_sweep_gradient_patches (&paint->current_body (), - paint->precision, - stops.arrayZ, - stops.length, - hb_color_line_get_extend (color_line), - cx, cy, - 32767.f, - start_angle, - end_angle); -} - -static void -hb_vector_paint_push_group (hb_paint_funcs_t *, - void *paint_data, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - paint->group_stack.push (hb_vector_t {}); -} - -static void -hb_vector_paint_pop_group (hb_paint_funcs_t *, - void *paint_data, - hb_paint_composite_mode_t mode, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - if (paint->group_stack.length < 2) - return; - - hb_vector_t group = paint->group_stack.pop (); - auto &body = paint->current_body (); - - const char *blend = hb_svg_composite_mode_str (mode); - if (blend) - { - hb_svg_append_str (&body, "\n"); - hb_svg_append_len (&body, group.arrayZ, group.length); - hb_svg_append_str (&body, "\n"); - } - else - hb_svg_append_len (&body, group.arrayZ, group.length); -} - -static hb_bool_t -hb_vector_paint_color_glyph (hb_paint_funcs_t *, - void *paint_data, - hb_codepoint_t glyph, - hb_font_t *font, - void *) -{ - auto *paint = (hb_vector_paint_t *) paint_data; - hb_vector_paint_ensure_initialized (paint); - hb_codepoint_t old_gid = paint->current_svg_image_glyph; - hb_face_t *old_face = paint->current_face; - paint->current_svg_image_glyph = glyph; - paint->current_face = hb_font_get_face (font); - hb_font_paint_glyph (font, glyph, - hb_vector_paint_funcs_get (), - paint, - paint->palette, - paint->foreground); - paint->current_svg_image_glyph = old_gid; - paint->current_face = old_face; - return true; -} - - - -/** - * hb_vector_paint_create_or_fail: - * @format: output format. - * - * Creates a new paint context for vector output. - * - * Return value: (nullable): a newly allocated #hb_vector_paint_t, or `NULL` on failure. - * - * Since: 13.0.0 - */ -hb_vector_paint_t * -hb_vector_paint_create_or_fail (hb_vector_format_t format) -{ - if (format != HB_VECTOR_FORMAT_SVG) - return nullptr; - - hb_vector_paint_t *paint = hb_object_create (); - if (unlikely (!paint)) - return nullptr; - paint->format = format; - - paint->defined_outlines = hb_set_create (); - paint->defined_clips = hb_set_create (); - paint->defs.alloc (4096); - paint->path.alloc (2048); - paint->subset_body_scratch.alloc (2048); - paint->captured_scratch.alloc (4096); - paint->color_stops_scratch.alloc (16); - - return paint; -} - -/** - * hb_vector_paint_reference: - * @paint: a paint context. - * - * Increases the reference count of @paint. - * - * Return value: (transfer full): referenced @paint. - * - * Since: 13.0.0 - */ -hb_vector_paint_t * -hb_vector_paint_reference (hb_vector_paint_t *paint) -{ - return hb_object_reference (paint); -} - -/** - * hb_vector_paint_destroy: - * @paint: a paint context. - * - * Decreases the reference count of @paint and destroys it when it reaches zero. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_destroy (hb_vector_paint_t *paint) -{ - if (!hb_object_destroy (paint)) return; - hb_blob_destroy (paint->recycled_blob); - hb_set_destroy (paint->defined_outlines); - hb_set_destroy (paint->defined_clips); - hb_free (paint); -} - -/** - * hb_vector_paint_set_user_data: - * @paint: a paint context. - * @key: user-data key. - * @data: user-data value. - * @destroy: (nullable): destroy callback for @data. - * @replace: whether to replace an existing value for @key. - * - * Attaches user data to @paint. - * - * Return value: `true` on success, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_paint_set_user_data (hb_vector_paint_t *paint, - hb_user_data_key_t *key, - void *data, - hb_destroy_func_t destroy, - hb_bool_t replace) -{ - return hb_object_set_user_data (paint, key, data, destroy, replace); -} - -/** - * hb_vector_paint_get_user_data: - * @paint: a paint context. - * @key: user-data key. - * - * Gets previously attached user data from @paint. - * - * Return value: (nullable): user-data value associated with @key. - * - * Since: 13.0.0 - */ -void * -hb_vector_paint_get_user_data (hb_vector_paint_t *paint, - hb_user_data_key_t *key) -{ - return hb_object_get_user_data (paint, key); -} - -/** - * hb_vector_paint_set_transform: - * @paint: a paint context. - * @xx: transform xx component. - * @yx: transform yx component. - * @xy: transform xy component. - * @yy: transform yy component. - * @dx: transform x translation. - * @dy: transform y translation. - * - * Sets the affine transform used when painting glyphs. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_transform (hb_vector_paint_t *paint, - float xx, float yx, - float xy, float yy, - float dx, float dy) -{ - paint->transform = {xx, yx, xy, yy, dx, dy}; -} - -/** - * hb_vector_paint_get_transform: - * @paint: a paint context. - * @xx: (out) (nullable): transform xx component. - * @yx: (out) (nullable): transform yx component. - * @xy: (out) (nullable): transform xy component. - * @yy: (out) (nullable): transform yy component. - * @dx: (out) (nullable): transform x translation. - * @dy: (out) (nullable): transform y translation. - * - * Gets the affine transform used when painting glyphs. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_get_transform (hb_vector_paint_t *paint, - float *xx, float *yx, - float *xy, float *yy, - float *dx, float *dy) -{ - if (xx) *xx = paint->transform.xx; - if (yx) *yx = paint->transform.yx; - if (xy) *xy = paint->transform.xy; - if (yy) *yy = paint->transform.yy; - if (dx) *dx = paint->transform.x0; - if (dy) *dy = paint->transform.y0; -} - -/** - * hb_vector_paint_set_scale_factor: - * @paint: a paint context. - * @x_scale_factor: x scale factor. - * @y_scale_factor: y scale factor. - * - * Sets additional output scaling factors. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_scale_factor (hb_vector_paint_t *paint, - float x_scale_factor, - float y_scale_factor) -{ - paint->x_scale_factor = x_scale_factor > 0.f ? x_scale_factor : 1.f; - paint->y_scale_factor = y_scale_factor > 0.f ? y_scale_factor : 1.f; -} - -/** - * hb_vector_paint_get_scale_factor: - * @paint: a paint context. - * @x_scale_factor: (out) (nullable): x scale factor. - * @y_scale_factor: (out) (nullable): y scale factor. - * - * Gets additional output scaling factors. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_get_scale_factor (hb_vector_paint_t *paint, - float *x_scale_factor, - float *y_scale_factor) -{ - if (x_scale_factor) *x_scale_factor = paint->x_scale_factor; - if (y_scale_factor) *y_scale_factor = paint->y_scale_factor; -} - -/** - * hb_vector_paint_set_extents: - * @paint: a paint context. - * @extents: (nullable): output extents to set or expand. - * - * Sets or expands output extents on @paint. Passing `NULL` clears extents. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_extents (hb_vector_paint_t *paint, - const hb_vector_extents_t *extents) -{ - if (!extents) - { - paint->extents = {0, 0, 0, 0}; - paint->has_extents = false; - return; - } - - if (!(extents->width > 0.f && extents->height > 0.f)) - return; - - if (paint->has_extents) - { - float x0 = hb_min (paint->extents.x, extents->x); - float y0 = hb_min (paint->extents.y, extents->y); - float x1 = hb_max (paint->extents.x + paint->extents.width, - extents->x + extents->width); - float y1 = hb_max (paint->extents.y + paint->extents.height, - extents->y + extents->height); - paint->extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - paint->extents = *extents; - paint->has_extents = true; - } -} - -/** - * hb_vector_paint_get_extents: - * @paint: a paint context. - * @extents: (out) (nullable): where to store current output extents. - * - * Gets current output extents from @paint. - * - * Return value: `true` if extents are set, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_paint_get_extents (hb_vector_paint_t *paint, - hb_vector_extents_t *extents) -{ - if (!paint->has_extents) - return false; - - if (extents) - *extents = paint->extents; - return true; -} - -/** - * hb_vector_paint_set_glyph_extents: - * @paint: a paint context. - * @glyph_extents: glyph extents in font units. - * - * Expands @paint extents using @glyph_extents under the current transform. - * - * Return value: `true` on success, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_paint_set_glyph_extents (hb_vector_paint_t *paint, - const hb_glyph_extents_t *glyph_extents) -{ - hb_bool_t has_extents = paint->has_extents; - hb_bool_t ret = hb_svg_set_glyph_extents_common (paint->transform, - paint->x_scale_factor, - paint->y_scale_factor, - glyph_extents, - &paint->extents, - &has_extents); - paint->has_extents = has_extents; - return ret; -} - -/** - * hb_vector_paint_set_foreground: - * @paint: a paint context. - * @foreground: foreground color used for COLR foreground paints. - * - * Sets fallback foreground color used by paint operations. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_foreground (hb_vector_paint_t *paint, - hb_color_t foreground) -{ - paint->foreground = foreground; -} - -/** - * hb_vector_paint_set_palette: - * @paint: a paint context. - * @palette: palette index for color glyph painting. - * - * Sets the color palette index used by paint operations. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_palette (hb_vector_paint_t *paint, - int palette) -{ - paint->palette = palette; -} - -/** - * hb_vector_paint_set_custom_palette_color: - * @paint: a paint context. - * @color_index: color index to override. - * @color: replacement color. - * - * Overrides one font palette color entry for subsequent paint operations. - * Overrides are keyed by @color_index and persist on @paint until cleared - * (or replaced for the same index). - * - * These overrides are consulted by paint operations that resolve CPAL - * entries, including SVG glyph content using `var(--colorN)`. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_set_custom_palette_color (hb_vector_paint_t *paint, - unsigned color_index, - hb_color_t color) -{ - paint->custom_palette_colors.set (color_index, color); -} - -/** - * hb_vector_paint_clear_custom_palette_colors: - * @paint: a paint context. - * - * Clears all custom palette color overrides previously set on @paint. - * - * After this call, palette lookups use the selected font palette without - * custom override entries. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_clear_custom_palette_colors (hb_vector_paint_t *paint) -{ - paint->custom_palette_colors.clear (); -} - -/** - * hb_vector_paint_get_funcs: - * - * Gets paint callbacks implemented by the vector paint backend. - * - * Return value: (transfer none): immutable #hb_paint_funcs_t singleton. - * - * Since: 13.0.0 - */ -hb_paint_funcs_t * -hb_vector_paint_get_funcs (void) -{ - return hb_vector_paint_funcs_get (); -} - -static hb_bool_t -hb_vector_paint_custom_palette_color (hb_paint_funcs_t *pfuncs HB_UNUSED, - void *paint_data, - unsigned color_index, - hb_color_t *color, - void *user_data HB_UNUSED) -{ - hb_vector_paint_t *paint = (hb_vector_paint_t *) paint_data; - if (!paint || !color) - return false; - - hb_color_t *value = nullptr; - if (!paint->custom_palette_colors.has (color_index, &value) || !value) - return false; - *color = *value; - return true; -} - -/** - * hb_vector_paint_glyph: - * @paint: a paint context. - * @font: font object. - * @glyph: glyph ID. - * @pen_x: glyph x origin before context transform. - * @pen_y: glyph y origin before context transform. - * @extents_mode: extents update mode. - * - * Paints one color glyph into @paint. - * - * Return value: `true` if glyph paint data was emitted, `false` otherwise. - * - * Since: 13.0.0 - */ -hb_bool_t -hb_vector_paint_glyph (hb_vector_paint_t *paint, - hb_font_t *font, - hb_codepoint_t glyph, - float pen_x, - float pen_y, - hb_vector_extents_mode_t extents_mode) -{ - float xx = paint->transform.xx; - float yx = paint->transform.yx; - float xy = paint->transform.xy; - float yy = paint->transform.yy; - float tx = paint->transform.x0 + xx * pen_x + xy * pen_y; - float ty = paint->transform.y0 + yx * pen_x + yy * pen_y; - - if (extents_mode == HB_VECTOR_EXTENTS_MODE_EXPAND) - { - hb_glyph_extents_t ge; - if (hb_font_get_glyph_extents (font, glyph, &ge)) - { - hb_bool_t has_extents = paint->has_extents; - hb_transform_t<> extents_transform = {xx, yx, -xy, -yy, tx, ty}; - hb_bool_t ret = hb_svg_set_glyph_extents_common (extents_transform, - paint->x_scale_factor, - paint->y_scale_factor, - &ge, - &paint->extents, - &has_extents); - paint->has_extents = has_extents; - (void) ret; - } - } - - hb_vector_paint_ensure_initialized (paint); - - bool can_cache = !paint->flat; - hb_svg_color_glyph_cache_key_t cache_key = hb_svg_color_glyph_cache_key (glyph, - (unsigned) paint->palette, - paint->foreground); - if (can_cache) - { - if (paint->defined_color_glyphs.has (cache_key)) - { - uint64_t entry = paint->defined_color_glyphs.get (cache_key); - unsigned def_id = hb_svg_cache_entry_def_id (entry); - bool image_like = hb_svg_cache_entry_image_like (entry); - auto &body = paint->current_body (); - hb_svg_append_str (&body, "precision, - paint->x_scale_factor, - paint->y_scale_factor, - tx, ty); - else - hb_svg_append_instance_transform (&body, paint->precision, - paint->x_scale_factor, - paint->y_scale_factor, - xx, yx, xy, yy, tx, ty); - hb_svg_append_str (&body, "\"/>\n"); - return true; - } - } - - bool has_svg_image = false; - if (can_cache) - { - paint->group_stack.push (hb_vector_t {}); - paint->current_color_glyph_has_svg_image = false; - } - - if (can_cache) - { - hb_codepoint_t old_gid = paint->current_svg_image_glyph; - hb_face_t *old_face = paint->current_face; - paint->current_svg_image_glyph = glyph; - paint->current_face = hb_font_get_face (font); - hb_bool_t ret = hb_font_paint_glyph_or_fail (font, glyph, - hb_vector_paint_get_funcs (), paint, - (unsigned) paint->palette, - paint->foreground); - paint->current_svg_image_glyph = old_gid; - paint->current_face = old_face; - if (unlikely (!ret)) - { - paint->group_stack.pop (); - return false; - } - - paint->captured_scratch = paint->group_stack.pop (); - has_svg_image = paint->current_color_glyph_has_svg_image; - if (unlikely (!paint->captured_scratch.length)) - return false; - - unsigned def_id = paint->color_glyph_counter++; - if (unlikely (!paint->defined_color_glyphs.set (cache_key, - hb_svg_pack_color_glyph_cache_entry (def_id, - has_svg_image)))) - return false; - - hb_svg_append_str (&paint->defs, "defs, def_id); - hb_svg_append_str (&paint->defs, "\">\n"); - hb_svg_append_len (&paint->defs, - paint->captured_scratch.arrayZ, - paint->captured_scratch.length); - hb_svg_append_str (&paint->defs, "\n"); - - auto &body = paint->current_body (); - hb_svg_append_str (&body, "precision, - paint->x_scale_factor, - paint->y_scale_factor, - tx, ty); - else - hb_svg_append_instance_transform (&body, paint->precision, - paint->x_scale_factor, - paint->y_scale_factor, - xx, yx, xy, yy, tx, ty); - hb_svg_append_str (&body, "\"/>\n"); - return true; - } - - auto &body = paint->current_body (); - hb_svg_append_str (&body, "precision, - paint->x_scale_factor, - paint->y_scale_factor, - xx, yx, xy, yy, tx, ty); - hb_svg_append_str (&body, "\">\n"); - hb_codepoint_t old_gid = paint->current_svg_image_glyph; - hb_face_t *old_face = paint->current_face; - paint->current_svg_image_glyph = glyph; - paint->current_face = hb_font_get_face (font); - hb_bool_t ret = hb_font_paint_glyph_or_fail (font, glyph, - hb_vector_paint_get_funcs (), paint, - (unsigned) paint->palette, - paint->foreground); - paint->current_svg_image_glyph = old_gid; - paint->current_face = old_face; - hb_svg_append_str (&body, "\n"); - return ret; -} - -/** - * hb_vector_svg_paint_set_flat: - * @paint: a paint context. - * @flat: whether to flatten paint output and disable glyph-group reuse. - * - * Enables or disables SVG paint flattening. - * - * Since: 13.0.0 - */ -void -hb_vector_svg_paint_set_flat (hb_vector_paint_t *paint, - hb_bool_t flat) -{ - paint->flat = !!flat; -} - -/** - * hb_vector_svg_paint_set_precision: - * @paint: a paint context. - * @precision: decimal precision. - * - * Sets numeric output precision for SVG paint output. - * - * Since: 13.0.0 - */ -void -hb_vector_svg_paint_set_precision (hb_vector_paint_t *paint, - unsigned precision) -{ - paint->precision = hb_min (precision, 12u); -} - -static void -hb_vector_paint_clear_render_state (hb_vector_paint_t *paint) -{ - paint->extents = {0, 0, 0, 0}; - paint->has_extents = false; - - paint->defs.clear (); - paint->path.clear (); - paint->group_stack.clear (); - paint->transform_group_open_mask = 0; - paint->transform_group_depth = 0; - paint->transform_group_overflow_depth = 0; - paint->clip_rect_counter = 0; - paint->gradient_counter = 0; - paint->color_glyph_counter = 0; - paint->current_color_glyph_has_svg_image = false; - paint->current_svg_image_glyph = HB_CODEPOINT_INVALID; - paint->current_face = nullptr; - paint->svg_image_counter = 0; - hb_set_clear (paint->defined_outlines); - hb_set_clear (paint->defined_clips); - paint->defined_color_glyphs.clear (); - paint->color_stops_scratch.clear (); - paint->subset_body_scratch.clear (); - paint->captured_scratch.clear (); -} - -/** - * hb_vector_paint_render: - * @paint: a paint context. - * - * Renders accumulated paint content to an SVG blob. - * - * Return value: (transfer full) (nullable): output blob, or `NULL` if rendering cannot proceed. - * - * Since: 13.0.0 - */ -hb_blob_t * -hb_vector_paint_render (hb_vector_paint_t *paint) -{ - if (paint->format != HB_VECTOR_FORMAT_SVG) - return nullptr; - if (!paint->has_extents) - return nullptr; - - hb_vector_paint_ensure_initialized (paint); - - hb_vector_t out; - hb_svg_recover_recycled_buffer (paint->recycled_blob, &out); - unsigned estimated = paint->defs.length + - paint->group_stack.arrayZ[0].length + - 320; - out.alloc (estimated); - hb_svg_append_str (&out, "extents.x, paint->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, paint->extents.y, paint->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, paint->extents.width, paint->precision); - hb_svg_append_c (&out, ' '); - hb_svg_append_num (&out, paint->extents.height, paint->precision); - hb_svg_append_str (&out, "\" width=\""); - hb_svg_append_num (&out, paint->extents.width, paint->precision); - hb_svg_append_str (&out, "\" height=\""); - hb_svg_append_num (&out, paint->extents.height, paint->precision); - hb_svg_append_str (&out, "\">\n"); - - if (paint->defs.length) - { - hb_svg_append_str (&out, "\n"); - hb_svg_append_len (&out, paint->defs.arrayZ, paint->defs.length); - hb_svg_append_str (&out, "\n"); - } - - paint->append_global_transform_prefix (&out); - hb_svg_append_len (&out, paint->group_stack.arrayZ[0].arrayZ, paint->group_stack.arrayZ[0].length); - paint->append_global_transform_suffix (&out); - - hb_svg_append_str (&out, "\n"); - - hb_blob_t *blob = hb_svg_blob_from_buffer (&paint->recycled_blob, &out); - - hb_vector_paint_clear_render_state (paint); - - return blob; -} - -/** - * hb_vector_paint_reset: - * @paint: a paint context. - * - * Resets @paint state and clears accumulated content. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_reset (hb_vector_paint_t *paint) -{ - paint->transform = {1, 0, 0, 1, 0, 0}; - paint->x_scale_factor = 1.f; - paint->y_scale_factor = 1.f; - paint->foreground = HB_COLOR (0, 0, 0, 255); - paint->palette = 0; - paint->precision = 2; - paint->flat = false; - hb_vector_paint_clear_render_state (paint); -} - -/** - * hb_vector_paint_recycle_blob: - * @paint: a paint context. - * @blob: (nullable): previously rendered blob to recycle. - * - * Provides a blob for internal buffer reuse by later render calls. - * - * Since: 13.0.0 - */ -void -hb_vector_paint_recycle_blob (hb_vector_paint_t *paint, - hb_blob_t *blob) -{ - hb_blob_destroy (paint->recycled_blob); - paint->recycled_blob = nullptr; - if (!blob || blob == hb_blob_get_empty ()) - return; - paint->recycled_blob = blob; -} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.cc deleted file mode 100644 index 286bc31a66..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-machinery.hh" -#include "hb-vector-svg-path.hh" -#include "hb-vector-svg-utils.hh" - -static void -hb_svg_path_move_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float to_x, float to_y, - void *) -{ - auto *s = (hb_svg_path_sink_t *) draw_data; - hb_svg_append_c (s->path, 'M'); - hb_svg_append_num (s->path, to_x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, to_y, s->precision); -} - -static void -hb_svg_path_line_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float to_x, float to_y, - void *) -{ - auto *s = (hb_svg_path_sink_t *) draw_data; - hb_svg_append_c (s->path, 'L'); - hb_svg_append_num (s->path, to_x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, to_y, s->precision); -} - -static void -hb_svg_path_quadratic_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float cx, float cy, - float to_x, float to_y, - void *) -{ - auto *s = (hb_svg_path_sink_t *) draw_data; - hb_svg_append_c (s->path, 'Q'); - hb_svg_append_num (s->path, cx, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, cy, s->precision); - hb_svg_append_c (s->path, ' '); - hb_svg_append_num (s->path, to_x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, to_y, s->precision); -} - -static void -hb_svg_path_cubic_to (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - float c1x, float c1y, - float c2x, float c2y, - float to_x, float to_y, - void *) -{ - auto *s = (hb_svg_path_sink_t *) draw_data; - hb_svg_append_c (s->path, 'C'); - hb_svg_append_num (s->path, c1x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, c1y, s->precision); - hb_svg_append_c (s->path, ' '); - hb_svg_append_num (s->path, c2x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, c2y, s->precision); - hb_svg_append_c (s->path, ' '); - hb_svg_append_num (s->path, to_x, s->precision); - hb_svg_append_c (s->path, ','); - hb_svg_append_num (s->path, to_y, s->precision); -} - -static void -hb_svg_path_close_path (hb_draw_funcs_t *, - void *draw_data, - hb_draw_state_t *, - void *) -{ - auto *s = (hb_svg_path_sink_t *) draw_data; - hb_svg_append_c (s->path, 'Z'); -} - -static inline void -free_static_svg_path_draw_funcs (); - -static struct hb_svg_path_draw_funcs_lazy_loader_t - : hb_draw_funcs_lazy_loader_t -{ - static hb_draw_funcs_t *create () - { - hb_draw_funcs_t *funcs = hb_draw_funcs_create (); - hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) hb_svg_path_move_to, nullptr, nullptr); - hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) hb_svg_path_line_to, nullptr, nullptr); - hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) hb_svg_path_quadratic_to, nullptr, nullptr); - hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) hb_svg_path_cubic_to, nullptr, nullptr); - hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) hb_svg_path_close_path, nullptr, nullptr); - hb_draw_funcs_make_immutable (funcs); - hb_atexit (free_static_svg_path_draw_funcs); - return funcs; - } -} static_svg_path_draw_funcs; - -static inline void -free_static_svg_path_draw_funcs () -{ - static_svg_path_draw_funcs.free_instance (); -} - -hb_draw_funcs_t * -hb_svg_path_draw_funcs_get (void) -{ - return static_svg_path_draw_funcs.get_unconst (); -} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.hh deleted file mode 100644 index 7e3b25c198..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-path.hh +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_VECTOR_SVG_PATH_HH -#define HB_VECTOR_SVG_PATH_HH - -#include "hb.hh" -#include "hb-vector.hh" -#include "hb-draw.h" - -struct hb_svg_path_sink_t -{ - hb_vector_t *path; - unsigned precision; -}; - -HB_INTERNAL hb_draw_funcs_t * -hb_svg_path_draw_funcs_get (void); - -#endif /* HB_VECTOR_SVG_PATH_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.cc deleted file mode 100644 index 12b7f95817..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.cc +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-face.hh" -#include "hb-vector-svg-subset.hh" -#include "OT/Color/svg/svg.hh" -#include "hb-vector-svg-utils.hh" -#include "hb-map.hh" -#include "hb-ot-color.h" - -#include -#include -#include - -static bool -hb_svg_append_with_prefix (hb_vector_t *out, - const char *s, - unsigned n, - const char *prefix, - unsigned prefix_len) -{ - unsigned i = 0; - while (i < n) - { - if (i + 4 <= n && !memcmp (s + i, "id=\"", 4)) - { - if (!hb_svg_append_len (out, s + i, 4)) return false; - i += 4; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '"') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 4 <= n && !memcmp (s + i, "id='", 4)) - { - if (!hb_svg_append_len (out, s + i, 4)) return false; - i += 4; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '\'') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 7 <= n && !memcmp (s + i, "href=\"#", 7)) - { - if (!hb_svg_append_len (out, s + i, 7)) return false; - i += 7; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '"') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 7 <= n && !memcmp (s + i, "href='#", 7)) - { - if (!hb_svg_append_len (out, s + i, 7)) return false; - i += 7; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '\'') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 13 <= n && !memcmp (s + i, "xlink:href=\"#", 13)) - { - if (!hb_svg_append_len (out, s + i, 13)) return false; - i += 13; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '"') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 13 <= n && !memcmp (s + i, "xlink:href='#", 13)) - { - if (!hb_svg_append_len (out, s + i, 13)) return false; - i += 13; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '\'') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 5 <= n && !memcmp (s + i, "url(#", 5)) - { - if (!hb_svg_append_len (out, s + i, 5)) return false; - i += 5; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != ')') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 6 <= n && !memcmp (s + i, "url(\"#", 6)) - { - if (!hb_svg_append_len (out, s + i, 6)) return false; - i += 6; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '"') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (i + 6 <= n && !memcmp (s + i, "url('#", 6)) - { - if (!hb_svg_append_len (out, s + i, 6)) return false; - i += 6; - if (!hb_svg_append_len (out, prefix, prefix_len)) return false; - while (i < n && s[i] != '\'') - { - if (!hb_svg_append_c (out, s[i])) return false; - i++; - } - continue; - } - if (!hb_svg_append_c (out, s[i])) - return false; - i++; - } - return true; -} - -static bool -hb_svg_add_unique_id (hb_vector_t *v, - hb_hashmap_t *seen_ids, - const char *p, - unsigned n) -{ - if (!n) return false; - OT::SVG::svg_id_span_t key = {p, n}; - if (seen_ids->has (key)) - return false; - if (unlikely (!seen_ids->set (key, true))) - return false; - auto *slot = v->push (); - if (!slot) return false; - *slot = key; - return true; -} - -static bool -hb_svg_collect_refs (const char *s, - unsigned n, - hb_vector_t *ids, - hb_hashmap_t *seen_ids) -{ - unsigned i = 0; - while (i < n) - { - if (i + 7 <= n && !memcmp (s + i, "href=\"#", 7)) - { - i += 7; - unsigned b = i; - while (i < n && s[i] != '"' && s[i] != '\'' && s[i] != ' ' && s[i] != '>') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 7 <= n && !memcmp (s + i, "href='#", 7)) - { - i += 7; - unsigned b = i; - while (i < n && s[i] != '\'' && s[i] != '"' && s[i] != ' ' && s[i] != '>') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 13 <= n && !memcmp (s + i, "xlink:href=\"#", 13)) - { - i += 13; - unsigned b = i; - while (i < n && s[i] != '"' && s[i] != '\'' && s[i] != ' ' && s[i] != '>') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 13 <= n && !memcmp (s + i, "xlink:href='#", 13)) - { - i += 13; - unsigned b = i; - while (i < n && s[i] != '\'' && s[i] != '"' && s[i] != ' ' && s[i] != '>') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 5 <= n && !memcmp (s + i, "url(#", 5)) - { - i += 5; - unsigned b = i; - while (i < n && s[i] != ')') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 6 <= n && !memcmp (s + i, "url(\"#", 6)) - { - i += 6; - unsigned b = i; - while (i < n && s[i] != '"') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - if (i + 6 <= n && !memcmp (s + i, "url('#", 6)) - { - i += 6; - unsigned b = i; - while (i < n && s[i] != '\'') i++; - if (i > b && unlikely (!hb_svg_add_unique_id (ids, seen_ids, s + b, i - b))) return false; - continue; - } - i++; - } - return true; -} - -bool -hb_svg_subset_glyph_image (hb_face_t *face, - hb_blob_t *image, - hb_codepoint_t glyph, - unsigned *image_counter, - hb_vector_t *defs_dst, - hb_vector_t *body_dst) -{ - if (glyph == HB_CODEPOINT_INVALID || !image_counter || !defs_dst || !body_dst) - return false; - - unsigned len; - const char *svg = hb_blob_get_data (image, &len); - if (!svg || !len) - return false; - - unsigned doc_index = 0; - if (!hb_ot_color_glyph_get_svg_document_index (face, glyph, &doc_index)) - return false; - - hb_codepoint_t start_glyph = HB_CODEPOINT_INVALID; - hb_codepoint_t end_glyph = HB_CODEPOINT_INVALID; - if (!hb_ot_color_get_svg_document_glyph_range (face, doc_index, &start_glyph, &end_glyph)) - return false; - - auto *doc_cache = face->table.SVG->get_or_create_doc_cache (image, svg, len, - doc_index, start_glyph, end_glyph); - if (!doc_cache) - return false; - svg = face->table.SVG->doc_cache_get_svg (doc_cache, &len); - - unsigned glyph_start = 0, glyph_end = 0; - if (!face->table.SVG->doc_cache_get_glyph_span (doc_cache, glyph, &glyph_start, &glyph_end)) - return false; - - auto *defs_entries = face->table.SVG->doc_cache_get_defs_entries (doc_cache); - - hb_vector_t needed_ids; - needed_ids.alloc (16); - hb_hashmap_t needed_ids_set; - if (!hb_svg_collect_refs (svg + glyph_start, glyph_end - glyph_start, - &needed_ids, &needed_ids_set)) - return false; - - hb_vector_t chosen_defs; - chosen_defs.alloc (16); - hb_vector_t chosen_def_marks; - if (unlikely (!chosen_def_marks.resize ((int) defs_entries->length))) - return false; - hb_memset (chosen_def_marks.arrayZ, 0, defs_entries->length); - for (unsigned qi = 0; qi < needed_ids.length; qi++) - { - const auto &need = needed_ids.arrayZ[qi]; - for (unsigned i = 0; i < defs_entries->length; i++) - { - const auto &e = defs_entries->arrayZ[i]; - if (e.id.len == need.len && !memcmp (e.id.p, need.p, need.len)) - { - if (!chosen_def_marks.arrayZ[i]) - { - chosen_def_marks.arrayZ[i] = 1; - if (unlikely (!chosen_defs.push (i))) - return false; - if (!hb_svg_collect_refs (svg + e.start, e.end - e.start, - &needed_ids, &needed_ids_set)) - return false; - } - break; - } - } - } - - char prefix[32]; - int prefix_len = snprintf (prefix, sizeof (prefix), "hbimg%u_", (*image_counter)++); - if (prefix_len <= 0 || (unsigned) prefix_len >= sizeof (prefix)) - return false; - - body_dst->alloc (body_dst->length + (glyph_end - glyph_start) + (unsigned) prefix_len + 32); - - for (unsigned i = 0; i < chosen_defs.length; i++) - { - const auto &e = defs_entries->arrayZ[chosen_defs.arrayZ[i]]; - if (!hb_svg_append_with_prefix (defs_dst, svg + e.start, e.end - e.start, prefix, (unsigned) prefix_len)) - return false; - if (!hb_svg_append_c (defs_dst, '\n')) return false; - } - - return hb_svg_append_with_prefix (body_dst, - svg + glyph_start, - glyph_end - glyph_start, - prefix, - (unsigned) prefix_len); -} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.hh deleted file mode 100644 index 32cb66c8d1..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-subset.hh +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_VECTOR_SVG_SUBSET_HH -#define HB_VECTOR_SVG_SUBSET_HH - -#include "hb.hh" -#include "hb-vector.hh" -#include "hb-blob.hh" -#include "hb-face.h" - -HB_INTERNAL bool -hb_svg_subset_glyph_image (hb_face_t *face, - hb_blob_t *image, - hb_codepoint_t glyph, - unsigned *image_counter, - hb_vector_t *defs_dst, - hb_vector_t *body_dst); - - -#endif /* HB_VECTOR_SVG_SUBSET_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.cc deleted file mode 100644 index 5a6ce55807..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#include "hb.hh" - -#include "hb-machinery.hh" -#include "hb-vector-svg-utils.hh" - -#include - -struct hb_svg_decimal_point_t -{ - char value[8]; -}; - -static hb_svg_decimal_point_t hb_svg_decimal_point_default = {{'.', '\0'}}; - -static inline void free_static_svg_decimal_point (); - -static struct hb_svg_decimal_point_lazy_loader_t - : hb_lazy_loader_t -{ - static hb_svg_decimal_point_t *create () - { - auto *p = (hb_svg_decimal_point_t *) hb_calloc (1, sizeof (hb_svg_decimal_point_t)); - if (!p) - return nullptr; - - p->value[0] = '.'; - p->value[1] = '\0'; - -#ifndef HB_NO_SETLOCALE -#if defined(HAVE_XLOCALE_H) - lconv *lc = nullptr; - hb_locale_t current_locale = hb_uselocale ((hb_locale_t) 0); - if (current_locale) - lc = localeconv_l (current_locale); - if (lc && lc->decimal_point && lc->decimal_point[0]) - { - strncpy (p->value, lc->decimal_point, sizeof (p->value) - 1); - p->value[sizeof (p->value) - 1] = '\0'; - } -#endif -#endif - - hb_atexit (free_static_svg_decimal_point); - return p; - } - - static void destroy (hb_svg_decimal_point_t *p) - { hb_free (p); } - - static const hb_svg_decimal_point_t *get_null () - { return &hb_svg_decimal_point_default; } -} static_svg_decimal_point; - -static inline void -free_static_svg_decimal_point () -{ - static_svg_decimal_point.free_instance (); -} - -const char * -hb_svg_decimal_point_get (void) -{ - return static_svg_decimal_point.get_unconst ()->value; -} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.hh deleted file mode 100644 index 11c733c96c..0000000000 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector-svg-utils.hh +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright © 2026 Behdad Esfahbod - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Author(s): Behdad Esfahbod - */ - -#ifndef HB_VECTOR_SVG_UTILS_HH -#define HB_VECTOR_SVG_UTILS_HH - -#include "hb.hh" -#include "hb-vector.hh" -#include -#include -#include - -HB_INTERNAL const char * -hb_svg_decimal_point_get (void); - -static inline bool -hb_svg_append_len (hb_vector_t *buf, - const char *s, - unsigned len) -{ - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + len)))) - return false; - hb_memcpy (buf->arrayZ + old_len, s, len); - return true; -} - -static inline bool -hb_svg_append_c (hb_vector_t *buf, char c) -{ - return !!buf->push (c); -} - -static inline void -hb_svg_append_num (hb_vector_t *buf, - float v, - unsigned precision, - bool keep_nonzero = false) -{ - unsigned effective_precision = precision; - if (effective_precision > 12) - effective_precision = 12; - if (keep_nonzero && v != 0.f) - while (effective_precision < 12) - { - float rounded_zero_threshold = 0.5f; - for (unsigned i = 0; i < effective_precision; i++) - rounded_zero_threshold *= 0.1f; - if (fabsf (v) >= rounded_zero_threshold) - break; - effective_precision++; - } - - float rounded_zero_threshold = 0.5f; - for (unsigned i = 0; i < effective_precision; i++) - rounded_zero_threshold *= 0.1f; - if (fabsf (v) < rounded_zero_threshold) - v = 0.f; - - if (!(v == v) || !isfinite (v)) - { - hb_svg_append_c (buf, '0'); - return; - } - - static const char float_formats[13][6] = { - "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f", - "%.7f", "%.8f", "%.9f", "%.10f", "%.11f", "%.12f", - }; - char out[128]; - snprintf (out, sizeof (out), float_formats[effective_precision], (double) v); - - const char *decimal_point = hb_svg_decimal_point_get (); - - if (decimal_point[0] != '.' || decimal_point[1] != '\0') - { - char *p = strstr (out, decimal_point); - if (p) - { - unsigned dp_len = (unsigned) strlen (decimal_point); - unsigned tail_len = (unsigned) strlen (p + dp_len); - memmove (p + 1, p + dp_len, tail_len + 1); - *p = '.'; - } - } - - char *dot = strchr (out, '.'); - if (dot) - { - char *end = out + strlen (out) - 1; - while (end > dot && *end == '0') - *end-- = '\0'; - if (end == dot) - *end = '\0'; - } - - hb_svg_append_len (buf, out, (unsigned) strlen (out)); -} - -static inline unsigned -hb_svg_scale_precision (unsigned precision) -{ - return precision < 7 ? 7 : precision; -} - -#endif /* HB_VECTOR_SVG_UTILS_HH */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.cc index 2b42225350..2d98059f9a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.cc @@ -26,7 +26,8 @@ #include "hb.hh" -#include "hb-vector.h" +#include "hb-machinery.hh" +#include "hb-vector-buf.hh" /** * SECTION:hb-vector @@ -34,8 +35,102 @@ * @short_description: Glyph vector conversion * @include: hb-vector.h * - * Functions for converting glyph draw and paint callbacks to vector output. + * Functions for converting glyph outlines and color paint trees + * into SVG or PDF vector output. * - * The initial backend is SVG. Extents must be set before calling render - * functions; otherwise render returns `NULL`. + * #hb_vector_draw_t converts monochrome glyph outlines into vector + * paths. Typical flow: + * + * |[ + * hb_vector_draw_t *draw = hb_vector_draw_create_or_fail (HB_VECTOR_FORMAT_SVG); + * hb_vector_draw_set_scale_factor (draw, 64.f, 64.f); + * hb_vector_draw_set_foreground (draw, foreground); + * hb_vector_draw_glyph (draw, font, gid, pen_x, pen_y); + * hb_blob_t *svg = hb_vector_draw_render (draw); + * ]| + * + * #hb_vector_paint_t renders color paint graphs (COLRv0/v1) and + * embedded PNG images into vector output with gradients, layers, + * and compositing. Typical flow: + * + * |[ + * hb_vector_paint_t *paint = hb_vector_paint_create_or_fail (HB_VECTOR_FORMAT_SVG); + * hb_vector_paint_set_scale_factor (paint, 64.f, 64.f); + * hb_vector_paint_set_foreground (paint, foreground); + * hb_vector_paint_glyph (paint, font, gid, pen_x, pen_y, + * HB_VECTOR_EXTENTS_MODE_EXPAND); + * hb_blob_t *svg = hb_vector_paint_render (paint); + * ]| + * + * Both contexts accumulate multiple glyphs into a single document. + * Call hb_vector_draw_render() / hb_vector_paint_render() to + * retrieve the final blob. Rendering clears all accumulated + * content (including extents), so retrieve any needed extents + * via hb_vector_draw_get_extents() / hb_vector_paint_get_extents() + * before rendering. + * + * Each glyph is emitted as an independent element. If glyphs + * overlap and the foreground color is semi-transparent, the + * overlapping regions will be composited separately rather than + * painted as a single uniform layer. **/ + +struct hb_vector_decimal_point_t +{ + char value[8]; +}; + +static hb_vector_decimal_point_t hb_vector_decimal_point_default = {{'.', '\0'}}; + +static inline void free_static_svg_decimal_point (); + +static struct hb_vector_decimal_point_lazy_loader_t + : hb_lazy_loader_t +{ + static hb_vector_decimal_point_t *create () + { + auto *p = (hb_vector_decimal_point_t *) hb_calloc (1, sizeof (hb_vector_decimal_point_t)); + if (!p) + return nullptr; + + p->value[0] = '.'; + p->value[1] = '\0'; + +#ifndef HB_NO_SETLOCALE + lconv *lc = nullptr; +#ifdef HAVE_LOCALECONV_L + hb_locale_t current_locale = hb_uselocale ((hb_locale_t) 0); + if (current_locale) + lc = localeconv_l (current_locale); +#endif + if (!lc) + lc = localeconv (); + if (lc && lc->decimal_point && lc->decimal_point[0]) + { + strncpy (p->value, lc->decimal_point, sizeof (p->value) - 1); + p->value[sizeof (p->value) - 1] = '\0'; + } +#endif + + hb_atexit (free_static_svg_decimal_point); + return p; + } + + static void destroy (hb_vector_decimal_point_t *p) + { hb_free (p); } + + static const hb_vector_decimal_point_t *get_null () + { return &hb_vector_decimal_point_default; } +} static_svg_decimal_point; + +static inline void +free_static_svg_decimal_point () +{ + static_svg_decimal_point.free_instance (); +} + +const char * +hb_vector_decimal_point_get (void) +{ + return static_svg_decimal_point.get_unconst ()->value; +} diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.h index dd32f2ec8b..0e555b80cd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.h @@ -35,6 +35,7 @@ HB_BEGIN_DECLS * hb_vector_format_t: * @HB_VECTOR_FORMAT_INVALID: Invalid format. * @HB_VECTOR_FORMAT_SVG: SVG output. + * @HB_VECTOR_FORMAT_PDF: PDF output. * * Output format for vector conversion. * @@ -43,6 +44,7 @@ HB_BEGIN_DECLS typedef enum { HB_VECTOR_FORMAT_INVALID = HB_TAG_NONE, HB_VECTOR_FORMAT_SVG = HB_TAG ('s','v','g',' '), + HB_VECTOR_FORMAT_PDF = HB_TAG ('p','d','f',' '), } hb_vector_format_t; /** @@ -75,6 +77,8 @@ typedef enum { HB_VECTOR_EXTENTS_MODE_EXPAND = 1, } hb_vector_extents_mode_t; +/* hb_vector_draw_t */ + /** * hb_vector_draw_t: * @@ -84,17 +88,6 @@ typedef enum { */ typedef struct hb_vector_draw_t hb_vector_draw_t; -/** - * hb_vector_paint_t: - * - * Opaque paint context for vector color-glyph conversion. - * - * Since: 13.0.0 - */ -typedef struct hb_vector_paint_t hb_vector_paint_t; - -/* hb_vector_draw_t */ - HB_EXTERN hb_vector_draw_t * hb_vector_draw_create_or_fail (hb_vector_format_t format); @@ -112,7 +105,7 @@ hb_vector_draw_set_user_data (hb_vector_draw_t *draw, hb_bool_t replace); HB_EXTERN void * -hb_vector_draw_get_user_data (hb_vector_draw_t *draw, +hb_vector_draw_get_user_data (const hb_vector_draw_t *draw, hb_user_data_key_t *key); HB_EXTERN void @@ -122,7 +115,7 @@ hb_vector_draw_set_transform (hb_vector_draw_t *draw, float dx, float dy); HB_EXTERN void -hb_vector_draw_get_transform (hb_vector_draw_t *draw, +hb_vector_draw_get_transform (const hb_vector_draw_t *draw, float *xx, float *yx, float *xy, float *yy, float *dx, float *dy); @@ -133,7 +126,7 @@ hb_vector_draw_set_scale_factor (hb_vector_draw_t *draw, float y_scale_factor); HB_EXTERN void -hb_vector_draw_get_scale_factor (hb_vector_draw_t *draw, +hb_vector_draw_get_scale_factor (const hb_vector_draw_t *draw, float *x_scale_factor, float *y_scale_factor); @@ -142,35 +135,61 @@ hb_vector_draw_set_extents (hb_vector_draw_t *draw, const hb_vector_extents_t *extents); HB_EXTERN hb_bool_t -hb_vector_draw_get_extents (hb_vector_draw_t *draw, +hb_vector_draw_get_extents (const hb_vector_draw_t *draw, hb_vector_extents_t *extents); HB_EXTERN hb_bool_t hb_vector_draw_set_glyph_extents (hb_vector_draw_t *draw, const hb_glyph_extents_t *glyph_extents); -HB_EXTERN hb_draw_funcs_t * -hb_vector_draw_get_funcs (void); +HB_EXTERN hb_vector_format_t +hb_vector_draw_get_format (const hb_vector_draw_t *draw); -HB_EXTERN hb_bool_t +HB_EXTERN hb_draw_funcs_t * +hb_vector_draw_get_funcs (const hb_vector_draw_t *draw); + +HB_EXTERN void +hb_vector_draw_new_path (hb_vector_draw_t *draw); + +HB_EXTERN void hb_vector_draw_glyph (hb_vector_draw_t *draw, hb_font_t *font, hb_codepoint_t glyph, - float pen_x, - float pen_y, hb_vector_extents_mode_t extents_mode); -HB_EXTERN void -hb_vector_svg_set_flat (hb_vector_draw_t *draw, - hb_bool_t flat); +HB_EXTERN hb_bool_t +hb_vector_draw_glyph_or_fail (hb_vector_draw_t *draw, + hb_font_t *font, + hb_codepoint_t glyph, + hb_vector_extents_mode_t extents_mode); HB_EXTERN void -hb_vector_svg_set_precision (hb_vector_draw_t *draw, +hb_vector_draw_set_precision (hb_vector_draw_t *draw, unsigned precision); +HB_EXTERN unsigned +hb_vector_draw_get_precision (const hb_vector_draw_t *draw); + +HB_EXTERN void +hb_vector_draw_set_foreground (hb_vector_draw_t *draw, + hb_color_t foreground); + +HB_EXTERN hb_color_t +hb_vector_draw_get_foreground (const hb_vector_draw_t *draw); + +HB_EXTERN void +hb_vector_draw_set_background (hb_vector_draw_t *draw, + hb_color_t background); + +HB_EXTERN hb_color_t +hb_vector_draw_get_background (const hb_vector_draw_t *draw); + HB_EXTERN hb_blob_t * hb_vector_draw_render (hb_vector_draw_t *draw); +HB_EXTERN void +hb_vector_draw_clear (hb_vector_draw_t *draw); + HB_EXTERN void hb_vector_draw_reset (hb_vector_draw_t *draw); @@ -181,6 +200,15 @@ hb_vector_draw_recycle_blob (hb_vector_draw_t *draw, /* hb_vector_paint_t */ +/** + * hb_vector_paint_t: + * + * Opaque paint context for vector color-glyph conversion. + * + * Since: 13.0.0 + */ +typedef struct hb_vector_paint_t hb_vector_paint_t; + HB_EXTERN hb_vector_paint_t * hb_vector_paint_create_or_fail (hb_vector_format_t format); @@ -198,7 +226,7 @@ hb_vector_paint_set_user_data (hb_vector_paint_t *paint, hb_bool_t replace); HB_EXTERN void * -hb_vector_paint_get_user_data (hb_vector_paint_t *paint, +hb_vector_paint_get_user_data (const hb_vector_paint_t *paint, hb_user_data_key_t *key); HB_EXTERN void @@ -208,7 +236,7 @@ hb_vector_paint_set_transform (hb_vector_paint_t *paint, float dx, float dy); HB_EXTERN void -hb_vector_paint_get_transform (hb_vector_paint_t *paint, +hb_vector_paint_get_transform (const hb_vector_paint_t *paint, float *xx, float *yx, float *xy, float *yy, float *dx, float *dy); @@ -219,7 +247,7 @@ hb_vector_paint_set_scale_factor (hb_vector_paint_t *paint, float y_scale_factor); HB_EXTERN void -hb_vector_paint_get_scale_factor (hb_vector_paint_t *paint, +hb_vector_paint_get_scale_factor (const hb_vector_paint_t *paint, float *x_scale_factor, float *y_scale_factor); @@ -228,7 +256,7 @@ hb_vector_paint_set_extents (hb_vector_paint_t *paint, const hb_vector_extents_t *extents); HB_EXTERN hb_bool_t -hb_vector_paint_get_extents (hb_vector_paint_t *paint, +hb_vector_paint_get_extents (const hb_vector_paint_t *paint, hb_vector_extents_t *extents); HB_EXTERN hb_bool_t @@ -239,10 +267,23 @@ HB_EXTERN void hb_vector_paint_set_foreground (hb_vector_paint_t *paint, hb_color_t foreground); +HB_EXTERN hb_color_t +hb_vector_paint_get_foreground (const hb_vector_paint_t *paint); + +HB_EXTERN void +hb_vector_paint_set_background (hb_vector_paint_t *paint, + hb_color_t background); + +HB_EXTERN hb_color_t +hb_vector_paint_get_background (const hb_vector_paint_t *paint); + HB_EXTERN void hb_vector_paint_set_palette (hb_vector_paint_t *paint, int palette); +HB_EXTERN int +hb_vector_paint_get_palette (const hb_vector_paint_t *paint); + HB_EXTERN void hb_vector_paint_set_custom_palette_color (hb_vector_paint_t *paint, unsigned color_index, @@ -251,28 +292,44 @@ hb_vector_paint_set_custom_palette_color (hb_vector_paint_t *paint, HB_EXTERN void hb_vector_paint_clear_custom_palette_colors (hb_vector_paint_t *paint); -HB_EXTERN hb_paint_funcs_t * -hb_vector_paint_get_funcs (void); +HB_EXTERN hb_vector_format_t +hb_vector_paint_get_format (const hb_vector_paint_t *paint); -HB_EXTERN hb_bool_t +HB_EXTERN hb_paint_funcs_t * +hb_vector_paint_get_funcs (const hb_vector_paint_t *paint); + +HB_EXTERN void hb_vector_paint_glyph (hb_vector_paint_t *paint, hb_font_t *font, hb_codepoint_t glyph, - float pen_x, - float pen_y, hb_vector_extents_mode_t extents_mode); -HB_EXTERN void -hb_vector_svg_paint_set_flat (hb_vector_paint_t *paint, - hb_bool_t flat); +HB_EXTERN hb_bool_t +hb_vector_paint_glyph_or_fail (hb_vector_paint_t *paint, + hb_font_t *font, + hb_codepoint_t glyph, + hb_vector_extents_mode_t extents_mode); HB_EXTERN void -hb_vector_svg_paint_set_precision (hb_vector_paint_t *paint, +hb_vector_paint_set_precision (hb_vector_paint_t *paint, unsigned precision); +HB_EXTERN unsigned +hb_vector_paint_get_precision (const hb_vector_paint_t *paint); + +HB_EXTERN void +hb_vector_paint_set_svg_prefix (hb_vector_paint_t *paint, + const char *prefix); + +HB_EXTERN const char * +hb_vector_paint_get_svg_prefix (const hb_vector_paint_t *paint); + HB_EXTERN hb_blob_t * hb_vector_paint_render (hb_vector_paint_t *paint); +HB_EXTERN void +hb_vector_paint_clear (hb_vector_paint_t *paint); + HB_EXTERN void hb_vector_paint_reset (hb_vector_paint_t *paint); @@ -282,4 +339,12 @@ hb_vector_paint_recycle_blob (hb_vector_paint_t *paint, HB_END_DECLS + +#if defined(__cplusplus) && defined(HB_CPLUSPLUS_HH) +namespace hb { +HB_DEFINE_VTABLE (vector_draw, nullptr); +HB_DEFINE_VTABLE (vector_paint, nullptr); +} // namespace hb +#endif + #endif /* HB_VECTOR_H */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.hh index e04632a636..e831c72b46 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-vector.hh @@ -182,7 +182,15 @@ struct hb_vector_t { if (unlikely (in_error ())) reset_error (); - resize (0); + clear (); + return *this; + } + + HB_ALWAYS_INLINE_VECTOR_ALLOCS + hb_vector_t &reset_if_error () + { + if (unlikely (in_error ())) + reset (); return *this; } @@ -264,7 +272,7 @@ struct hb_vector_t const Type& tail () const { return (*this)[length - 1]; } explicit operator bool () const { return length; } - unsigned get_size () const { return length * item_size; } + size_t get_size () const { return length * item_size; } /* Sink interface. */ template @@ -318,6 +326,12 @@ struct hb_vector_t } template HB_ALWAYS_INLINE_VECTOR_ALLOCS + bool push_or_fail (Args&&... args) + { + return push (std::forward (args)...) != std::addressof (Crap (Type)); + } + template + HB_ALWAYS_INLINE_VECTOR_ALLOCS Type *push_has_room (Args&&... args) { /* Emplace. */ @@ -571,7 +585,7 @@ struct hb_vector_t HB_ALWAYS_INLINE_VECTOR_ALLOCS void clear () { - resize (0); + shrink_vector (0); } template @@ -699,8 +713,11 @@ struct hb_vector_t /* Sorting API. */ - void qsort (int (*cmp)(const void*, const void*) = Type::cmp) - { as_array ().qsort (cmp); } + template + void qsort (Compar compar) + { as_array ().qsort (compar); } + void qsort () + { as_array ().qsort (); } /* Unsorted search API. */ template diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-version.h b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-version.h index f72e7fc72e..f44973e60d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-version.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-version.h @@ -41,13 +41,13 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 13 +#define HB_VERSION_MAJOR 14 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 0 +#define HB_VERSION_MINOR 2 /** * HB_VERSION_MICRO: * @@ -60,7 +60,7 @@ HB_BEGIN_DECLS * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "13.0.0" +#define HB_VERSION_STRING "14.2.0" /** * HB_VERSION_ATLEAST: diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc index f83329e1c1..885ddffe95 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc @@ -169,40 +169,35 @@ _hb_wasm_shaper_face_data_create (hb_face_t *face) { char error[128]; hb_wasm_face_data_t *data = nullptr; - hb_blob_t *wasm_blob = nullptr; wasm_module_t wasm_module = nullptr; - wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM); + hb_unique_ptr_t wasm_blob (hb_face_reference_table (face, HB_WASM_TAG_WASM)); + unsigned length = hb_blob_get_length (wasm_blob); if (!length) - goto fail; + return nullptr; if (!_hb_wasm_init ()) - goto fail; + return nullptr; wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr), length, error, sizeof (error)); if (unlikely (!wasm_module)) { DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error); - goto fail; + return nullptr; } + auto module_guard = hb_make_scope_guard ([&]() { wasm_runtime_unload (wasm_module); }); data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t)); if (unlikely (!data)) - goto fail; + return nullptr; - data->wasm_blob = wasm_blob; + data->wasm_blob = wasm_blob.release (); data->wasm_module = wasm_module; + module_guard.release (); return data; - -fail: - if (wasm_module) - wasm_runtime_unload (wasm_module); - hb_blob_destroy (wasm_blob); - hb_free (data); - return nullptr; } static hb_wasm_shape_plan_t * @@ -217,30 +212,27 @@ acquire_shape_plan (hb_face_t *face, return plan; plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t)); - - wasm_module_inst_t module_inst = nullptr; - wasm_exec_env_t exec_env = nullptr; - wasm_function_inst_t func = nullptr; + auto plan_guard = hb_make_scope_guard ([&]() { hb_free (plan); }); constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024; - module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module, - stack_size, heap_size, - error, sizeof (error)); + wasm_module_inst_t module_inst = plan->module_inst = wasm_runtime_instantiate ( + face_data->wasm_module, stack_size, heap_size, error, sizeof (error)); if (unlikely (!module_inst)) { DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error); - goto fail; + return nullptr; } + auto module_guard = hb_make_scope_guard ([&]() { wasm_runtime_deinstantiate (module_inst); }); - exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst, - stack_size); + wasm_exec_env_t exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst, stack_size); if (unlikely (!exec_env)) { DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed."); - goto fail; + return nullptr; } + auto exec_guard = hb_make_scope_guard ([&]() { wasm_runtime_destroy_exec_env (exec_env); }); - func = wasm_runtime_lookup_function (module_inst, "shape_plan_create"); + wasm_function_inst_t func = wasm_runtime_lookup_function (module_inst, "shape_plan_create"); if (func) { wasm_val_t results[1]; @@ -250,7 +242,7 @@ acquire_shape_plan (hb_face_t *face, if (unlikely (!faceref)) { DEBUG_MSG (WASM, face_data, "Failed to register face object."); - goto fail; + return nullptr; } results[0].kind = WASM_I32; @@ -264,21 +256,15 @@ acquire_shape_plan (hb_face_t *face, { DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s", wasm_runtime_get_exception (module_inst)); - goto fail; + return nullptr; } plan->wasm_shape_planptr = results[0].of.i32; } + plan_guard.release (); + module_guard.release (); + exec_guard.release (); return plan; - -fail: - - if (exec_env) - wasm_runtime_destroy_exec_env (exec_env); - if (module_inst) - wasm_runtime_deinstantiate (module_inst); - hb_free (plan); - return nullptr; } static void diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb.hh b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb.hh index 2ebae65f20..7e2837f99a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb.hh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/harfbuzz-ng/src/hb.hh @@ -138,6 +138,7 @@ /* Ignored intentionally. */ #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_IGNORED +#pragma GCC diagnostic ignored "-Warray-bounds" // https://github.com/harfbuzz/harfbuzz/issues/5738 #pragma GCC diagnostic ignored "-Wclass-memaccess" #pragma GCC diagnostic ignored "-Wcast-function-type-strict" // https://github.com/harfbuzz/harfbuzz/pull/3859#issuecomment-1295409126 #pragma GCC diagnostic ignored "-Wdangling-reference" // https://github.com/harfbuzz/harfbuzz/issues/4043 @@ -570,6 +571,13 @@ extern "C" void hb_free_impl(void *ptr); #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector +/* Library-internal alias for hb::unique_ptr defined in hb-cplusplus.hh. + * Unique-ownership RAII wrapper around an HB object; destroys on scope exit + * via the type's hb_*_destroy() function. Usage: hb_unique_ptr_t. + * Matches the hb_*_t naming used elsewhere in internal code. */ +template using hb_unique_ptr_t = hb::unique_ptr; + + /* Our src/test-*.cc use hb_assert(), such that it's not compiled out under NDEBUG. * https://github.com/harfbuzz/harfbuzz/issues/5418 */ #define hb_always_assert(x) \ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/COPYRIGHT.txt b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/COPYRIGHT.txt index ce9d95bfeb..c86e0f22fd 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/COPYRIGHT.txt +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/COPYRIGHT.txt @@ -1,8 +1,8 @@ -Copyright (C) 2009-2024 D. R. Commander +Copyright (C) 2009-2026 D. R. Commander +Copyright (C) 2015-2016, 2018, 2022 Matthieu Darbois +Copyright (C) 2019-2021 Arm Limited Copyright (C) 2015, 2020 Google, Inc. -Copyright (C) 2019-2020 Arm Limited -Copyright (C) 2015-2016, 2018 Matthieu Darbois -Copyright (C) 2011-2016 Siarhei Siamashka +Copyright (C) 2011, 2014, 2016 Siarhei Siamashka Copyright (C) 2015 Intel Corporation Copyright (C) 2013-2014 Linaro Limited Copyright (C) 2013-2014 MIPS Technologies, Inc. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/ChangeLog.md b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/ChangeLog.md index 17390d80bd..e2d1eaf808 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/ChangeLog.md +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/ChangeLog.md @@ -1,3 +1,65 @@ +3.1.4 +===== + +### Significant changes relative to 3.1.3: + +1. Fixed an issue in the TurboJPEG 2.x compatibility wrapper whereby, if a +calling program attempted to decompress a lossless JPEG image using +`tjDecompress2()` with decompression scaling, the decompressed image was +unexpectedly unscaled. This could have led to a buffer overrun if the caller +allocated the packed-pixel destination buffer based on the assumption that the +decompressed image would be scaled down. + +2. The SIMD dispatchers now use `getauxval()` or `elf_aux_info()`, if +available, to detect support for Neon and AltiVec instructions on AArch32 and +PowerPC Linux, Android, and *BSD systems. + +3. Hardened the libjpeg API against hypothetical applications that may +erroneously set one of the exposed quantization table values to 0 just before +calling `jpeg_start_compress()`. (This would never happen in a +correctly-written program, because `jpeg_add_quant_table()` clamps all values +less than 1.) + +4. Fixed a division-by-zero error that occurred when attempting to use the +jpegtran `-drop` option with a specially-crafted malformed drop image +(specifically an image in which one or more of the quantization table values +was 0.) + +5. Fixed an issue in the TurboJPEG API library's data destination manager that +manifested as: + + - a memory leak that occurred if a pre-allocated JPEG destination buffer +was passed to `tj3Compress*()` or `tj3Transform()`, `TJPARAM_NOREALLOC` was +unset, and it was necessary for the library to re-allocate the buffer to +accommodate the destination image, and + - a potential caller double free that occurred if pre-allocated JPEG +destination buffers were passed to `tj3Transform()`, multiple lossless +transform operations were performed, and it was necessary for the library to +re-allocate the second buffer to accommodate the second destination image. + +6. Fixed an issue in `tj3Transform()` whereby, if `TJPARAM_SAVEMARKERS` was set +to 2 or 4, `TJXOPT_COPYNONE` was not specified, an ICC profile was extracted +from the source image, and another ICC profile was associated with the +TurboJPEG instance using `tj3SetICCProfile()`, both profiles were embedded in +the destination image. The documented API behavior is for `TJXOPT_COPYNONE` to +take precedence over `TJPARAM_SAVEMARKERS` and for `TJPARAM_SAVEMARKERS` to +take precedence over the associated ICC profile. Thus, `tj3Transform()` now +ignores the associated ICC profile unless `TJXOPT_COPYNONE` is specified or +`TJPARAM_SAVEMARKERS` is set to something other than 2 or 4. + +7. Fixed an oversight in the libjpeg API whereby, if a calling application +manually set `cinfo.Ss` (the predictor selection value) to a value less than 1 +or greater than 7 after calling `jpeg_enable_lossless()` and prior to calling +`jpeg_start_compress()`, an incorrect (all white) lossless JPEG image was +silently generated. + +8. Further hardened the TurboJPEG Java API against hypothetical applications +that may erroneously pass huge values to one of the compression, YUV encoding, +decompression, YUV decoding, or packed-pixel image I/O methods, leading to +signed integer overflow in the JNI wrapper's buffer size checks that rendered +those checks ineffective. + + 3.1.3 ===== @@ -91,8 +153,8 @@ instance, and setting `TJPARAM_LOSSLESS`/`TJ.PARAM_LOSSLESS` to `0` now disables lossless JPEG compression in a TurboJPEG instance. -3.1 beta1 -========= +3.0.90 (3.1 beta1) +================== ### Significant changes relative to 3.0.4: @@ -2227,8 +2289,8 @@ be used to build both OS X and iOS applications. ### Significant changes relative to 1.1.1: -1. Added a Java wrapper for the TurboJPEG API. See [java/README](java/README) -for more details. +1. Added a Java wrapper for the TurboJPEG API. See +[java/README.md](java/README.md) for more details. 2. The TurboJPEG API can now be used to scale down images during decompression. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/LICENSE b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/LICENSE index f299cf39e7..2ca7680d46 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/LICENSE +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/LICENSE @@ -94,8 +94,8 @@ intended solely for clarification. The Modified (3-clause) BSD License =================================== -Copyright (C)2009-2025 D. R. Commander. All Rights Reserved.
-Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. +Copyright (C) 2009-2026 D. R. Commander. All Rights Reserved.
+Copyright (C) 2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/README.md b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/README.md index 86b5ea676a..f2169476bc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/README.md +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/README.md @@ -368,8 +368,11 @@ Memory Debugger Pitfalls Valgrind and Memory Sanitizer (MSan) can generate false positives (specifically, incorrect reports of uninitialized memory accesses) when used -with libjpeg-turbo's SIMD extensions. It is generally recommended that the -SIMD extensions be disabled, either by passing an argument of `-DWITH_SIMD=0` -to `cmake` when configuring the build or by setting the environment variable -`JSIMD_FORCENONE` to `1` at run time, when testing libjpeg-turbo with Valgrind, -MSan, or other memory debuggers. +with libjpeg-turbo's SIMD extensions. There are two ways to work around this +when testing libjpeg-turbo with Valgrind, MSan, or other memory debuggers: + +1. Disable the SIMD extensions, either by passing an argument of + `-DWITH_SIMD=0` to `cmake` when configuring the build or by setting the + environment variable `JSIMD_FORCENONE` to `1` at run time. +2. Define the `ZERO_BUFFERS` preprocessor macro (for instance, by adding + `-DZERO_BUFFERS=1` to `CMAKE_C_FLAGS`.) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/qt_attribution.json b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/qt_attribution.json index 5ac811a12b..67b1db6e45 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/qt_attribution.json +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "The Independent JPEG Group's JPEG software", "Homepage": "http://libjpeg-turbo.virtualgl.org/", - "Version": "3.1.3", - "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.3/libjpeg-turbo-3.1.3.tar.gz", + "Version": "3.1.4", + "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.1.4/libjpeg-turbo-3.1.4.tar.gz", "PURL": "pkg:github/libjpeg-turbo/libjpeg-turbo@$", "CPE": "cpe:2.3:a:libjpeg-turbo:libjpeg-turbo:$:*:*:*:*:*:*:*", diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcdctmgr.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcdctmgr.c index dbdbad6a28..deb5314cfc 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcdctmgr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcdctmgr.c @@ -6,7 +6,7 @@ * libjpeg-turbo Modifications: * Copyright (C) 1999-2006, MIYASAKA Masaru. * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2011, 2014-2015, 2022, 2024, D. R. Commander. + * Copyright (C) 2011, 2014-2015, 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -23,6 +23,9 @@ #include "jsimddct.h" +#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || \ + defined(DCT_FLOAT_SUPPORTED) + /* Private subobject for this module */ typedef void (*forward_DCT_method_ptr) (DCTELEM *data); @@ -176,11 +179,17 @@ compute_reciprocal(UINT16 divisor, DCTELEM *dtbl) UDCTELEM c; int b, r; - if (divisor == 1) { + if (divisor <= 1) { /* divisor == 1 means unquantized, so these reciprocal/correction/shift * values will cause the C quantization algorithm to act like the * identity function. Since only the C quantization algorithm is used in * these cases, the scale value is irrelevant. + * + * divisor == 0 can never happen in a normal program, because + * jpeg_add_quant_table() clamps values < 1. However, a program could + * abuse the API by manually modifying the exposed quantization table just + * before calling jpeg_start_compress(). Thus, we effectively clamp + * values < 1 here as well, to avoid dividing by 0. */ dtbl[DCTSIZE2 * 0] = (DCTELEM)1; /* reciprocal */ dtbl[DCTSIZE2 * 1] = (DCTELEM)0; /* correction */ @@ -746,3 +755,6 @@ _jinit_forward_dct(j_compress_ptr cinfo) #endif } } + +#endif /* defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || + defined(DCT_FLOAT_SUPPORTED) */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jchuff.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jchuff.c index 781e1ca704..5c766767b6 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jchuff.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jchuff.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2014-2016, 2018-2025, D. R. Commander. + * Copyright (C) 2009-2011, 2014-2016, 2018-2026, D. R. Commander. * Copyright (C) 2015, Matthieu Darbois. * Copyright (C) 2018, Matthias Räncker. * Copyright (C) 2020, Arm Limited. @@ -947,7 +947,10 @@ GLOBAL(void) jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[]) { #define MAX_CLEN 32 /* assumed maximum initial code length */ - UINT8 bits[MAX_CLEN + 1]; /* bits[k] = # of symbols with code length k */ + /* The array length is MAX_CLEN + 2 rather than MAX_CLEN + 1 to work around a + * -Wstringop-overflow false positive with GCC 12 and later. + */ + UINT8 bits[MAX_CLEN + 2]; /* bits[k] = # of symbols with code length k */ int bit_pos[MAX_CLEN + 1]; /* # of symbols with smaller code length */ int codesize[257]; /* codesize[k] = code length of symbol k */ int nz_index[257]; /* index of nonzero symbol in the original freq diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcinit.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcinit.c index 09ff6b3e43..01fd409c12 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcinit.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcinit.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2020, 2022, 2024, D. R. Commander. + * Copyright (C) 2020, 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -91,6 +91,8 @@ jinit_compress_master(j_compress_ptr cinfo) ERREXIT(cinfo, JERR_NOT_COMPILED); #endif } else { +#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || \ + defined(DCT_FLOAT_SUPPORTED) /* Forward DCT */ if (cinfo->data_precision == 8) jinit_forward_dct(cinfo); @@ -123,6 +125,9 @@ jinit_compress_master(j_compress_ptr cinfo) else jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 || cinfo->optimize_coding)); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif } if (cinfo->data_precision <= 8) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclhuff.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclhuff.c index ae4154532e..6f3b375297 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclhuff.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclhuff.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2022, D. R. Commander. + * Copyright (C) 2022, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -190,7 +190,9 @@ start_pass_lhuff(j_compress_ptr cinfo, boolean gather_statistics) entropy->input_ptr_index[sampn] = ptrn; /* Precalculate which tables to use for each sample */ entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no]; +#ifdef ENTROPY_OPT_SUPPORTED entropy->cur_counts[sampn] = entropy->count_ptrs[compptr->dc_tbl_no]; +#endif } } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclossls.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclossls.c index 295c3e2a2b..80afd9e481 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclossls.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jclossls.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2022, 2024, D. R. Commander. + * Copyright (C) 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -228,6 +228,9 @@ jpeg_difference_first_row(j_compress_ptr cinfo, int ci, case 7: losslessc->predict_difference[ci] = jpeg_difference7; break; + default: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); } } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcmaster.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcmaster.c index 1dcd252b3c..a301727a14 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcmaster.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcmaster.c @@ -7,7 +7,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2016, 2018, 2022-2024, D. R. Commander. + * Copyright (C) 2010, 2016, 2018, 2022-2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -276,11 +276,11 @@ validate_script(j_compress_ptr cinfo) */ { const jpeg_scan_info *scanptr; - int scanno, ncomps, ci, coefi, thisi; + int scanno, ncomps, ci, thisi; int Ss, Se, Ah, Al; boolean component_sent[MAX_COMPONENTS]; #ifdef C_PROGRESSIVE_SUPPORTED - int *last_bitpos_ptr; + int coefi, *last_bitpos_ptr; int last_bitpos[MAX_COMPONENTS][DCTSIZE2]; /* -1 until that coefficient has been seen; then last Al for it */ #endif @@ -619,8 +619,8 @@ prepare_for_pass(j_compress_ptr cinfo) */ master->pass_type = output_pass; master->pass_number++; -#endif FALLTHROUGH /*FALLTHROUGH*/ +#endif case output_pass: /* Do a data-output pass. */ /* We need not repeat per-scan setup if prior optimization pass did it. */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfig.h b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfig.h index 85a1509fb6..5c8bf7273d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfig.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfig.h @@ -2,9 +2,9 @@ #define JPEG_LIB_VERSION 80 -#define LIBJPEG_TURBO_VERSION 3.1.3 +#define LIBJPEG_TURBO_VERSION 3.1.4 -#define LIBJPEG_TURBO_VERSION_NUMBER 3001003 +#define LIBJPEG_TURBO_VERSION_NUMBER 3001004 #define C_ARITH_CODING_SUPPORTED 1 diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfigint.h b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfigint.h index 6d5f963392..d2c2e3925d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfigint.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jconfigint.h @@ -10,7 +10,7 @@ #define PACKAGE_NAME "libjpeg-turbo" -#define VERSION "3.1.3" +#define VERSION "3.1.4" #if SIZE_MAX == 0xffffffff #define SIZEOF_SIZE_T 4 diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcphuff.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcphuff.c index 58287328d2..76f2d96dc4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcphuff.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcphuff.c @@ -217,7 +217,7 @@ start_pass_phuff(j_compress_ptr cinfo, boolean gather_statistics) if (entropy->bit_buffer == NULL) entropy->bit_buffer = (char *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, - MAX_CORR_BITS * sizeof(char)); + MAX_CORR_BITS); } } if (gather_statistics) diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcprepct.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcprepct.c index 725856d738..767e28ce07 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcprepct.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcprepct.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2022, 2024, D. R. Commander. + * Copyright (C) 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -38,21 +38,21 @@ /* - * For the simple (no-context-row) case, we just need to buffer one - * row group's worth of pixels for the downsampling step. At the bottom of - * the image, we pad to a full row group by replicating the last pixel row. - * The downsampler's last output row is then replicated if needed to pad - * out to a full iMCU row. + * For the simple (no-context-row) case, we just need to buffer one row group's + * worth of components for the downsampling step. At the bottom of the image, + * we pad to a full row group by replicating the last component row(s). The + * downsampler's last output row is then replicated if needed to pad out to a + * full iMCU row. * * When providing context rows, we must buffer three row groups' worth of - * pixels. Three row groups are physically allocated, but the row pointer + * components. Three row groups are physically allocated, but the row pointer * arrays are made five row groups high, with the extra pointers above and * below "wrapping around" to point to the last and first real row groups. - * This allows the downsampler to access the proper context rows. - * At the top and bottom of the image, we create dummy context rows by - * copying the first or last real pixel row. This copying could be avoided - * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the - * trouble on the compression side. + * This allows the downsampler to access the proper context rows. At the top + * and bottom of the image, we create dummy context rows by copying the first + * or last real component row(s). This copying could be avoided by pointer + * hacking, as is done in jdmainct.c, but it doesn't seem worth the trouble on + * the compression side. */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcsample.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcsample.c index ca3bea131f..6492cf6391 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcsample.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jcsample.c @@ -8,16 +8,16 @@ * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB * Copyright (C) 2014, MIPS Technologies, Inc., California. - * Copyright (C) 2015, 2019, 2022, 2024, D. R. Commander. + * Copyright (C) 2015, 2019, 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * * This file contains downsampling routines. * - * Downsampling input data is counted in "row groups". A row group - * is defined to be max_v_samp_factor pixel rows of each component, - * from which the downsampler produces v_samp_factor sample rows. - * A single row group is processed in each call to the downsampler module. + * Downsampling input data is counted in "row groups". A row group is defined + * to be max_v_samp_factor rows of each component, from which the downsampler + * produces v_samp_factor sample rows. A single row group is processed in each + * call to the downsampler module. * * The downsampler is responsible for edge-expansion of its output data * to fill an integral number of DCT blocks horizontally. The source buffer @@ -26,29 +26,29 @@ * The caller (the prep controller) is responsible for vertical padding. * * The downsampler may request "context rows" by setting need_context_rows - * during startup. In this case, the input arrays will contain at least - * one row group's worth of pixels above and below the passed-in data; - * the caller will create dummy rows at image top and bottom by replicating - * the first or last real pixel row. + * during startup. In this case, the input arrays will contain at least one + * row group's worth of components above and below the passed-in data; the + * caller will create dummy rows at image top and bottom by replicating the + * first or last real component row(s). * * An excellent reference for image resampling is * Digital Image Warping, George Wolberg, 1990. * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. * * The downsampling algorithm used here is a simple average of the source - * pixels covered by the output pixel. The hi-falutin sampling literature - * refers to this as a "box filter". In general the characteristics of a box - * filter are not very good, but for the specific cases we normally use (1:1 - * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not - * nearly so bad. If you intend to use other sampling ratios, you'd be well - * advised to improve this code. + * components covered by the output sample. The hi-falutin sampling literature + * refers to this as a "box filter". In general, the characteristics of a box + * filter are not very good. However, for the specific cases we normally use + * (1:1 and 2:1 ratios), the box is equivalent to a "triangle filter", which is + * not nearly so bad. If you intend to use other sampling ratios, you'd be + * well advised to improve this code. * * A simple input-smoothing capability is provided. This is mainly intended - * for cleaning up color-dithered GIF input files (if you find it inadequate, + * for cleaning up color-dithered GIF input files. (If you find it inadequate, * we suggest using an external filtering program such as pnmconvol). When - * enabled, each input pixel P is replaced by a weighted sum of itself and its - * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, - * where SF = (smoothing_factor / 1024). + * enabled, each input component C is replaced by a weighted sum of itself and + * its eight neighbors. C's weight is 1-8*SF, and each neighbor's weight is + * SF, where SF = (smoothing_factor / 1024). * Currently, smoothing is only supported for 2h2v sampling factors. */ @@ -142,7 +142,7 @@ sep_downsample(j_compress_ptr cinfo, _JSAMPIMAGE input_buf, /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * One row group is processed per call. * This version handles arbitrary integral sampling ratios, without smoothing. * Note that this version is not actually used for customary sampling ratios. @@ -191,7 +191,7 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * This version handles the special case of a full-size component, * without smoothing. */ @@ -212,7 +212,7 @@ fullsize_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * This version handles the common case of 2:1 horizontal and 1:1 vertical, * without smoothing. * @@ -255,7 +255,7 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * This version handles the standard case of 2:1 horizontal and 2:1 vertical, * without smoothing. */ @@ -298,7 +298,7 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, #ifdef INPUT_SMOOTHING_SUPPORTED /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * This version handles the standard case of 2:1 horizontal and 2:1 vertical, * with smoothing. One row of context is required. */ @@ -321,17 +321,17 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, cinfo->image_width, output_cols * 2); - /* We don't bother to form the individual "smoothed" input pixel values; + /* We don't bother to form the individual "smoothed" input component values; * we can directly compute the output which is the average of the four - * smoothed values. Each of the four member pixels contributes a fraction - * (1-8*SF) to its own smoothed image and a fraction SF to each of the three - * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final - * output. The four corner-adjacent neighbor pixels contribute a fraction - * SF to just one smoothed pixel, or SF/4 to the final output; while the - * eight edge-adjacent neighbors contribute SF to each of two smoothed - * pixels, or SF/2 overall. In order to use integer arithmetic, these - * factors are scaled by 2^16 = 65536. - * Also recall that SF = smoothing_factor / 1024. + * smoothed values. Each of the four member components contributes a + * fraction (1-8*SF) to its own smoothed image and a fraction SF to each of + * the three other smoothed components, therefore a total fraction (1-5*SF)/4 + * to the final output. The four corner-adjacent neighbor components + * contribute a fraction SF to just one smoothed component, or SF/4 to the + * final output; while the eight edge-adjacent neighbors contribute SF to + * each of two smoothed components, or SF/2 overall. In order to use integer + * arithmetic, these factors are scaled by 2^16 = 65536. Also recall that + * SF = smoothing_factor / 1024. */ memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */ @@ -356,9 +356,9 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2; for (colctr = output_cols - 2; colctr > 0; colctr--) { - /* sum of pixels directly mapped to this output element */ + /* sum of components directly mapped to this output element */ membersum = inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1]; - /* sum of edge-neighbor pixels */ + /* sum of edge-neighbor components */ neighsum = above_ptr[0] + above_ptr[1] + below_ptr[0] + below_ptr[1] + inptr0[-1] + inptr0[2] + inptr1[-1] + inptr1[2]; /* The edge-neighbors count twice as much as corner-neighbors */ @@ -387,7 +387,7 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, /* - * Downsample pixel values of a single component. + * Downsample components from a single plane. * This version handles the special case of a full-size component, * with smoothing. One row of context is required. */ @@ -411,10 +411,10 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2, cinfo->image_width, output_cols); - /* Each of the eight neighbor pixels contributes a fraction SF to the - * smoothed pixel, while the main pixel contributes (1-8*SF). In order - * to use integer arithmetic, these factors are multiplied by 2^16 = 65536. - * Also recall that SF = smoothing_factor / 1024. + /* Each of the eight neighbor components contributes a fraction SF to the + * smoothed component, while the main component contributes (1-8*SF). In + * order to use integer arithmetic, these factors are multiplied by + * 2^16 = 65536. Also recall that SF = smoothing_factor / 1024. */ memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */ @@ -468,7 +468,9 @@ _jinit_downsampler(j_compress_ptr cinfo) my_downsample_ptr downsample; int ci; jpeg_component_info *compptr; +#ifdef INPUT_SMOOTHING_SUPPORTED boolean smoothok = TRUE; +#endif #ifdef C_LOSSLESS_SUPPORTED if (cinfo->master->lossless) { @@ -511,7 +513,9 @@ _jinit_downsampler(j_compress_ptr cinfo) downsample->methods[ci] = fullsize_downsample; } else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor && compptr->v_samp_factor == cinfo->max_v_samp_factor) { +#ifdef INPUT_SMOOTHING_SUPPORTED smoothok = FALSE; +#endif #ifdef WITH_SIMD if (jsimd_can_h2v1_downsample()) downsample->methods[ci] = jsimd_h2v1_downsample; @@ -541,7 +545,9 @@ _jinit_downsampler(j_compress_ptr cinfo) } } else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 && (cinfo->max_v_samp_factor % compptr->v_samp_factor) == 0) { +#ifdef INPUT_SMOOTHING_SUPPORTED smoothok = FALSE; +#endif downsample->methods[ci] = int_downsample; } else ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdapistd.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdapistd.c index 813e21268e..4b915ece6c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdapistd.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdapistd.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2015-2020, 2022-2025, D. R. Commander. + * Copyright (C) 2010, 2015-2020, 2022-2026, D. R. Commander. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -408,7 +408,10 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines) void (*color_quantize) (j_decompress_ptr cinfo, _JSAMPARRAY input_buf, _JSAMPARRAY output_buf, int num_rows) = NULL; - if (!master->using_merged_upsample && cinfo->cconvert && + if (cinfo->cconvert && +#ifdef UPSAMPLE_MERGING_SUPPORTED + !master->using_merged_upsample && +#endif cinfo->cconvert->_color_convert) { color_convert = cinfo->cconvert->_color_convert; cinfo->cconvert->_color_convert = noop_convert; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jddctmgr.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jddctmgr.c index 0bd8c2b591..3a55e0e7c3 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jddctmgr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jddctmgr.c @@ -6,7 +6,7 @@ * Modified 2002-2010 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2010, 2015, 2022, D. R. Commander. + * Copyright (C) 2010, 2015, 2022, 2026, D. R. Commander. * Copyright (C) 2013, MIPS Technologies, Inc., California. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -29,6 +29,9 @@ #include "jpegapicomp.h" +#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || \ + defined(DCT_FLOAT_SUPPORTED) + /* * The decompressor input side (jdinput.c) saves away the appropriate * quantization table for each component at the start of the first scan @@ -363,3 +366,6 @@ _jinit_inverse_dct(j_decompress_ptr cinfo) idct->cur_method[ci] = -1; } } + +#endif /* defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || + defined(DCT_FLOAT_SUPPORTED) */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdlossls.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdlossls.c index 520755adc3..5517a697a1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdlossls.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdlossls.c @@ -6,7 +6,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2022, 2024, D. R. Commander. + * Copyright (C) 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -206,6 +206,9 @@ jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index, case 7: losslessd->predict_undifference[comp_index] = jpeg_undifference7; break; + default: + ERREXIT4(cinfo, JERR_BAD_PROGRESSION, + cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al); } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmainct.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmainct.c index fc97073e3d..d9b0424fea 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmainct.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmainct.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2016, 2022, 2024, D. R. Commander. + * Copyright (C) 2010, 2016, 2022, 2024, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -36,8 +36,8 @@ * chosen such that these numbers are integers. In practice DCT_scaled_size * values will likely be powers of two, so we actually have the stronger * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) - * Upsampling will typically produce max_v_samp_factor pixel rows from each - * row group (times any additional scale factor that the upsampler is + * Upsampling will typically produce max_v_samp_factor rows of each component + * from each row group (times any additional scale factor that the upsampler is * applying). * * The coefficient or difference controller will deliver data to us one iMCU diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmaster.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmaster.c index 4085c22918..54a4c41eb2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmaster.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdmaster.c @@ -7,7 +7,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2016, 2019, 2022-2024, D. R. Commander. + * Copyright (C) 2009-2011, 2016, 2019, 2022-2024, 2026, D. R. Commander. * Copyright (C) 2013, Linaro Limited. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg @@ -675,6 +675,8 @@ master_selection(j_decompress_ptr cinfo) ERREXIT(cinfo, JERR_NOT_COMPILED); #endif } else { +#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED) || \ + defined(DCT_FLOAT_SUPPORTED) /* Inverse DCT */ if (cinfo->data_precision == 8) jinit_inverse_dct(cinfo); @@ -707,6 +709,9 @@ master_selection(j_decompress_ptr cinfo) j12init_d_coef_controller(cinfo, use_c_buffer); else jinit_d_coef_controller(cinfo, use_c_buffer); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif } if (!cinfo->raw_data_out) { diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.c index 022471dc37..ac446a396e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1996, Thomas G. Lane. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2010, 2015-2016, 2022, 2024-2025, D. R. Commander. + * Copyright (C) 2010, 2015-2016, 2022, 2024-2026, D. R. Commander. * Copyright (C) 2014, MIPS Technologies, Inc., California. * Copyright (C) 2015, Google, Inc. * Copyright (C) 2019-2020, Arm Limited. @@ -14,11 +14,11 @@ * * This file contains upsampling routines. * - * Upsampling input data is counted in "row groups". A row group - * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) - * sample rows of each component. Upsampling will normally produce - * max_v_samp_factor pixel rows from each row group (but this could vary - * if the upsampler is applying a scale factor of its own). + * Upsampling input data is counted in "row groups". A row group is defined to + * be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) sample rows of + * each component. Upsampling will normally produce max_v_samp_factor rows of + * each component from each row group (but this could vary if the upsampler is + * applying a scale factor of its own). * * An excellent reference for image resampling is * Digital Image Warping, George Wolberg, 1990. @@ -113,8 +113,8 @@ sep_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf, /* - * These are the routines invoked by sep_upsample to upsample pixel values - * of a single component. One row group is processed per call. + * These are the routines invoked by sep_upsample to upsample values of a + * single component. One row group is processed per call. */ @@ -148,13 +148,13 @@ noop_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, /* * This version handles any integral sampling ratios. - * This is not used for typical JPEG files, so it need not be fast. - * Nor, for that matter, is it particularly accurate: the algorithm is - * simple replication of the input pixel onto the corresponding output - * pixels. The hi-falutin sampling literature refers to this as a - * "box filter". A box filter tends to introduce visible artifacts, - * so if you are actually going to use 3:1 or 4:1 sampling ratios - * you would be well advised to improve this code. + * This is not used for typical JPEG files, so it need not be fast. Nor, for + * that matter, is it particularly accurate: the algorithm is simple + * replication of the input sample onto the corresponding output components. + * The hi-falutin sampling literature refers to this as a "box filter". A box + * filter tends to introduce visible artifacts, so if you are actually going to + * use 3:1 or 4:1 sampling ratios you would be well advised to improve this + * code. */ METHODDEF(void) @@ -260,10 +260,10 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, /* * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. * - * The upsampling algorithm is linear interpolation between pixel centers, - * also known as a "triangle filter". This is a good compromise between - * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 - * of the way between input pixel centers. + * The upsampling algorithm is linear interpolation between component centers, + * also known as a "triangle filter". This is a good compromise between speed + * and visual quality. The centers of the output components are 1/4 and 3/4 of + * the way between input component centers. * * A note about the "bias" calculations: when rounding fractional values to * integer, we do not want to always round 0.5 up to the next integer. @@ -291,7 +291,7 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, *outptr++ = (_JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2); for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { - /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + /* General case: 3/4 * nearer component + 1/4 * further component */ invalue = (*inptr++) * 3; *outptr++ = (_JSAMPLE)((invalue + inptr[-2] + 1) >> 2); *outptr++ = (_JSAMPLE)((invalue + inptr[0] + 2) >> 2); @@ -391,8 +391,9 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, lastcolsum = thiscolsum; thiscolsum = nextcolsum; for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { - /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ - /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + /* General case: 3/4 * nearer component + 1/4 * further component in + * each dimension, thus 9/16, 3/16, 3/16, 1/16 overall + */ nextcolsum = (*inptr0++) * 3 + (*inptr1++); *outptr++ = (_JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4); *outptr++ = (_JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4); @@ -462,7 +463,7 @@ _jinit_upsampler(j_decompress_ptr cinfo) for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; ci++, compptr++) { /* Compute size of an "input group" after IDCT scaling. This many samples - * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + * are to be converted to max_h_samp_factor * max_v_samp_factor components. */ h_in_group = (compptr->h_samp_factor * compptr->_DCT_scaled_size) / cinfo->_min_DCT_scaled_size; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.h b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.h index a8a9298094..4957908d4d 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jdsample.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2022, D. R. Commander. + * Copyright (C) 2022, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. */ @@ -43,7 +43,7 @@ typedef struct { /* Height of an input row group for each component. */ int rowgroup_height[MAX_COMPONENTS]; - /* These arrays save pixel expansion factors so that int_expand need not + /* These arrays save component expansion factors so that int_expand need not * recompute them each time. They are unused for other upsampling methods. */ UINT8 h_expand[MAX_COMPONENTS]; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctint.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctint.c index c58592d626..991d06933c 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctint.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctint.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1998, Thomas G. Lane. * Modification developed 2002-2018 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015, 2020, 2022, D. R. Commander. + * Copyright (C) 2015, 2020, 2022, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -30,7 +30,7 @@ * * We also provide IDCT routines with various output sample block sizes for * direct resolution reduction or enlargement without additional resampling: - * NxN (N=1...16) pixels for one 8x8 input DCT block. + * NxN (N=1...16) samples for one 8x8 input DCT block. * * For N<8 we simply take the corresponding low-frequency coefficients of * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctred.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctred.c index 6521e3ebbf..8603f738fb 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctred.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jidctred.c @@ -4,12 +4,12 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1998, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2015, 2022, D. R. Commander. + * Copyright (C) 2015, 2022, 2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * * This file contains inverse-DCT routines that produce reduced-size output: - * either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. + * either 4x4, 2x2, or 1x1 samples from an 8x8 DCT block. * * The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) * algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step @@ -397,7 +397,7 @@ _jpeg_idct_1x1(j_decompress_ptr cinfo, jpeg_component_info *compptr, SHIFT_TEMPS /* We hardly need an inverse DCT routine for this: just take the - * average pixel value, which is one-eighth of the DC coefficient. + * average sample value, which is one-eighth of the DC coefficient. */ quantptr = (ISLOW_MULT_TYPE *)compptr->dct_table; dcval = DEQUANTIZE(coef_block[0], quantptr[0]); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmemmgr.c b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmemmgr.c index eb199c8b3d..494d04a159 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmemmgr.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmemmgr.c @@ -717,11 +717,11 @@ realize_virt_arrays(j_common_ptr cinfo) maximum_space = 0; for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { if (sptr->mem_buffer == NULL) { /* if not realized yet */ - size_t new_space = (long)sptr->rows_in_array * - (long)sptr->samplesperrow * sample_size; + size_t new_space = (size_t)sptr->rows_in_array * + (size_t)sptr->samplesperrow * sample_size; - space_per_minheight += (long)sptr->maxaccess * - (long)sptr->samplesperrow * sample_size; + space_per_minheight += (size_t)sptr->maxaccess * + (size_t)sptr->samplesperrow * sample_size; if (SIZE_MAX - maximum_space < new_space) out_of_memory(cinfo, 10); maximum_space += new_space; @@ -729,11 +729,11 @@ realize_virt_arrays(j_common_ptr cinfo) } for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { if (bptr->mem_buffer == NULL) { /* if not realized yet */ - size_t new_space = (long)bptr->rows_in_array * - (long)bptr->blocksperrow * sizeof(JBLOCK); + size_t new_space = (size_t)bptr->rows_in_array * + (size_t)bptr->blocksperrow * sizeof(JBLOCK); - space_per_minheight += (long)bptr->maxaccess * - (long)bptr->blocksperrow * sizeof(JBLOCK); + space_per_minheight += (size_t)bptr->maxaccess * + (size_t)bptr->blocksperrow * sizeof(JBLOCK); if (SIZE_MAX - maximum_space < new_space) out_of_memory(cinfo, 11); maximum_space += new_space; @@ -774,9 +774,9 @@ realize_virt_arrays(j_common_ptr cinfo) /* It doesn't fit in memory, create backing store. */ sptr->rows_in_mem = (JDIMENSION)(max_minheights * sptr->maxaccess); jpeg_open_backing_store(cinfo, &sptr->b_s_info, - (long)sptr->rows_in_array * - (long)sptr->samplesperrow * - (long)sample_size); + (long)((size_t)sptr->rows_in_array * + (size_t)sptr->samplesperrow * + sample_size)); sptr->b_s_open = TRUE; } sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, @@ -798,9 +798,9 @@ realize_virt_arrays(j_common_ptr cinfo) /* It doesn't fit in memory, create backing store. */ bptr->rows_in_mem = (JDIMENSION)(max_minheights * bptr->maxaccess); jpeg_open_backing_store(cinfo, &bptr->b_s_info, - (long)bptr->rows_in_array * - (long)bptr->blocksperrow * - (long)sizeof(JBLOCK)); + (long)((size_t)bptr->rows_in_array * + (size_t)bptr->blocksperrow * + sizeof(JBLOCK))); bptr->b_s_open = TRUE; } bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmorecfg.h b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmorecfg.h index 89c7842c87..a4df71c3ec 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmorecfg.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jmorecfg.h @@ -7,7 +7,8 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, 2022, D. R. Commander. + * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, 2022, 2026, + * D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -241,7 +242,9 @@ typedef int boolean; /* Encoder capability options: */ #define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires + C_MULTISCAN_FILES_SUPPORTED and + ENTROPY_OPT_SUPPORTED) */ #define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */ #define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ /* Note: if you selected 12-bit data precision, it is dangerous to turn off @@ -249,21 +252,22 @@ typedef int boolean; * precision, so jchuff.c normally uses entropy optimization to compute * usable tables for higher precision. If you don't want to do optimization, * you'll have to supply different default Huffman tables. - * The exact same statements apply for progressive and lossless JPEG: - * the default tables don't work for progressive mode or lossless mode. - * (This may get fixed, however.) + * The exact same statements apply for lossless JPEG: the default tables don't + * work for lossless mode. (This may get fixed, however.) */ #define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ /* Decoder capability options: */ #define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ -#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ -#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */ +#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires + D_MULTISCAN_FILES_SUPPORTED) */ +#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? (Requires + D_MULTISCAN_FILES_SUPPORTED) */ #define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */ #define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ -#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ -#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ +#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? (Requires + DCT_ISLOW_SUPPORTED) */ #define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ #define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ #define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jversion.h b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jversion.h index 0c127b5fa0..1900c19ab4 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jversion.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libjpeg/src/jversion.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2012-2024, D. R. Commander. + * Copyright (C) 2010, 2012-2026, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -37,11 +37,11 @@ */ #define JCOPYRIGHT1 \ - "Copyright (C) 2009-2024 D. R. Commander\n" \ + "Copyright (C) 2009-2026 D. R. Commander\n" \ + "Copyright (C) 2015-2016, 2018, 2022 Matthieu Darbois\n" \ + "Copyright (C) 2019-2021 Arm Limited\n" \ "Copyright (C) 2015, 2020 Google, Inc.\n" \ - "Copyright (C) 2019-2020 Arm Limited\n" \ - "Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \ - "Copyright (C) 2011-2016 Siarhei Siamashka\n" \ + "Copyright (C) 2011, 2014, 2016 Siarhei Siamashka\n" \ "Copyright (C) 2015 Intel Corporation\n" #define JCOPYRIGHT2 \ "Copyright (C) 2013-2014 Linaro Limited\n" \ @@ -53,4 +53,4 @@ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding\n" #define JCOPYRIGHT_SHORT \ - "Copyright (C) 1991-2025 The libjpeg-turbo Project and many others" + "Copyright (C) 1991-2026 The libjpeg-turbo Project and many others" diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/ANNOUNCE b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/ANNOUNCE index 5ada7ae879..02969b03e2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/ANNOUNCE +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/ANNOUNCE @@ -1,5 +1,5 @@ -libpng 1.6.55 - February 9, 2026 -================================ +libpng 1.6.58 - April 15, 2026 +============================== This is a public release of libpng, intended for use in production code. @@ -9,10 +9,10 @@ Files available for download Source files: - * libpng-1.6.55.tar.xz (LZMA-compressed, recommended) - * libpng-1.6.55.tar.gz (deflate-compressed) - * lpng1655.7z (LZMA-compressed) - * lpng1655.zip (deflate-compressed) + * libpng-1.6.58.tar.xz (LZMA-compressed, recommended) + * libpng-1.6.58.tar.gz (deflate-compressed) + * lpng1658.7z (LZMA-compressed) + * lpng1658.zip (deflate-compressed) Other information: @@ -22,14 +22,14 @@ Other information: * TRADEMARK.md -Changes from version 1.6.54 to version 1.6.55 +Changes from version 1.6.57 to version 1.6.58 --------------------------------------------- - * Fixed CVE-2026-25646 (high severity): - Heap buffer overflow in `png_set_quantize`. - (Reported and fixed by Joshua Inscoe.) - * Resolved an oss-fuzz build issue involving nalloc. - (Contributed by Philippe Antoine.) + * Fixed a regression introduced in version 1.6.56 that caused `png_get_PLTE` + to return stale palette data after applying gamma and background transforms + in-place. + (Reported by ralfjunker .) + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/CHANGES b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/CHANGES index af9fcff6eb..208ca6eaf1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/CHANGES +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/CHANGES @@ -6337,6 +6337,55 @@ Version 1.6.55 [February 9, 2026] Resolved an oss-fuzz build issue involving nalloc. (Contributed by Philippe Antoine.) +Version 1.6.56 [March 25, 2026] + Fixed CVE-2026-33416 (high severity): + Use-after-free via pointer aliasing in `png_set_tRNS` and `png_set_PLTE`. + (Reported by Halil Oktay and Ryo Shimada; + fixed by Halil Oktay and Cosmin Truta.) + Fixed CVE-2026-33636 (high severity): + Out-of-bounds read/write in the palette expansion on ARM Neon. + (Reported by Taegu Ha; fixed by Taegu Ha and Cosmin Truta.) + Fixed uninitialized reads beyond `num_trans` in `trans_alpha` buffers. + (Contributed by Halil Oktay.) + Fixed stale `info_ptr->palette` after in-place gamma and background + transforms. + Fixed wrong channel indices in `png_image_read_and_map` RGB_ALPHA path. + (Contributed by Yuelin Wang.) + Fixed wrong background color in colormap read. + (Contributed by Yuelin Wang.) + Fixed dead loop in sPLT write. + (Contributed by Yuelin Wang.) + Added missing null pointer checks in four public API functions. + (Contributed by Yuelin Wang.) + Validated shift bit depths in `png_set_shift` to prevent infinite loop. + (Contributed by Yuelin Wang.) + Avoided undefined behavior in library and tests. + Deprecated the hardly-ever-tested POINTER_INDEXING config option. + Added negative-stride test coverage for the simplified API. + Fixed memory leaks and API misuse in oss-fuzz. + (Contributed by Owen Sanzas.) + Implemented various fixes and improvements in oss-fuzz. + (Contributed by Bob Friesenhahn and Philippe Antoine.) + Performed various refactorings and cleanups. + +Version 1.6.57 [April 8, 2026] + Fixed CVE-2026-34757 (medium severity): + Use-after-free in `png_set_PLTE`, `png_set_tRNS` and `png_set_hIST` + leading to corrupted chunk data and potential heap information disclosure. + Also hardened the append-style setters (`png_set_text`, `png_set_sPLT`, + `png_set_unknown_chunks`) against a theoretical variant of the same + aliasing pattern. + (Reported by Iv4n .) + Fixed integer overflow in rowbytes computation in read transforms. + (Contributed by Mohammad Seet.) + +Version 1.6.58 [April 15, 2026] + Fixed a regression introduced in version 1.6.56 that caused `png_get_PLTE` + to return stale palette data after applying gamma and background transforms + in-place. + (Reported by ralfjunker .) + + Send comments/corrections/commendations to png-mng-implement at lists.sf.net. Subscription is required; visit diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/README b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/README index 6e0d1e3313..75a92ab723 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/README +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/README @@ -1,4 +1,4 @@ -README for libpng version 1.6.55 +README for libpng version 1.6.58 ================================ See the note about version numbers near the top of `png.h`. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/libpng-manual.txt b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/libpng-manual.txt index ca689d0102..4413ce9901 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/libpng-manual.txt +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/libpng-manual.txt @@ -9,7 +9,7 @@ libpng-manual.txt - A description on how to use and modify libpng Based on: - libpng version 1.6.36, December 2018, through 1.6.55 - February 2026 + libpng version 1.6.36, December 2018, through 1.6.58 - April 2026 Updated and distributed by Cosmin Truta Copyright (c) 2018-2026 Cosmin Truta @@ -2318,7 +2318,7 @@ libpng provides two macros to help you in 1.5 and later versions: png_uint_32 height = PNG_PASS_ROWS(image_height, pass_number); Respectively these tell you the width and height of the sub-image -corresponding to the numbered pass. 'pass' is in in the range 0 to 6 - +corresponding to the numbered pass. 'pass' is in the range 0 to 6 - this can be confusing because the specification refers to the same passes as 1 to 7! Be careful, you must check both the width and height before calling png_read_rows() and not call it for that pass if either is zero. @@ -2457,7 +2457,7 @@ point to libpng-allocated storage with the following function: This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. +by the user and not by libpng, and will in those cases do nothing. The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed. If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or @@ -3292,7 +3292,7 @@ disclaimer until after, so viewers working over modem connections don't have to wait for the disclaimer to go over the modem before they start seeing the image. Finally, keywords should be full words, not abbreviations. Keywords and text are in the ISO 8859-1 -(Latin-1) character set (a superset of regular ASCII) and can not +(Latin-1) character set (a superset of regular ASCII) and cannot contain NUL characters, and should not contain control or other unprintable characters. To make the comments widely readable, stick with basic ASCII, and avoid machine specific character set extensions @@ -3694,7 +3694,7 @@ point to libpng-allocated storage with the following function: This function may be safely called when the relevant storage has already been freed, or has not yet been allocated, or was allocated -by the user and not by libpng, and will in those cases do nothing. +by the user and not by libpng, and will in those cases do nothing. The "seq" parameter is ignored if only one item of the selected data type, such as PLTE, is allowed. If "seq" is not -1, and multiple items are allowed for the data type identified in the mask, such as text or diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.c index a0cad0197e..cebe7af1f8 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.c @@ -13,7 +13,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55; +typedef png_libpng_version_1_6_58 Your_png_h_is_not_version_1_6_58; /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the * corresponding macro definitions. This causes a compile time failure if @@ -820,7 +820,7 @@ png_get_copyright(png_const_structrp png_ptr) return PNG_STRING_COPYRIGHT #else return PNG_STRING_NEWLINE \ - "libpng version 1.6.55" PNG_STRING_NEWLINE \ + "libpng version 1.6.58" PNG_STRING_NEWLINE \ "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ @@ -1170,7 +1170,7 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) return 1; /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so - * the fillowing calculates (X+Y+Z) of the reference white (media white, + * the following calculates (X+Y+Z) of the reference white (media white, * encoding white) itself: */ d = dblue; @@ -1215,9 +1215,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * (-0.0770) because the PNG spec itself requires the xy values to be * unsigned. whitey is also required to be 5 or more to avoid overflow. * - * Instead the upper limits have been relaxed to accomodate ACES AP1 where + * Instead the upper limits have been relaxed to accommodate ACES AP1 where * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range." - * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy. + * The new limit accommodates the AP0 and AP1 ranges for z but not AP0 redy. */ const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10); if (xy->redx < 0 || xy->redx > fpLimit) return 1; @@ -1328,7 +1328,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * red-scale + green-scale + blue-scale = 1/white-y = white-scale * * So now we have a Cramer's rule solution where the determinants are just - * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve + * 3x3 - far more tractable. Unfortunately 3x3 determinants still involve * multiplication of three coefficients so we can't guarantee to avoid * overflow in the libpng fixed point representation. Using Cramer's rule in * floating point is probably a good choice here, but it's not an option for @@ -1697,7 +1697,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, * into R, G and B channels. * * Previously it was suggested that an RGB profile on grayscale data could be - * handled. However it it is clear that using an RGB profile in this context + * handled. However it is clear that using an RGB profile in this context * must be an error - there is no specification of what it means. Thus it is * almost certainly more correct to ignore the profile. */ @@ -2915,7 +2915,7 @@ png_gamma_significant(png_fixed_point gamma_val) * * 2.2/(2+51/256) == 1.00035524 * - * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/- + * I.e. vanishingly small (<4E-4) but still detectable in 16-bit linear (+/- * 23). Note that the Adobe choice seems to be something intended to give an * exact number with 8 binary fractional digits - it is the closest to 2.2 * that is possible a base 2 .8p representation. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.h b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.h index 38fd349e5f..1d98cc53e1 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/png.h @@ -1,6 +1,6 @@ /* png.h - header file for PNG reference library * - * libpng version 1.6.55 + * libpng version 1.6.58 * * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson @@ -14,7 +14,7 @@ * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.35, July 2018: * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.55, February 2026: + * libpng versions 1.6.36, December 2018, through 1.6.58, April 2026: * Cosmin Truta * See also "Contributing Authors", below. */ @@ -238,7 +238,7 @@ * ... * 1.5.30 15 10530 15.so.15.30[.0] * ... - * 1.6.55 16 10655 16.so.16.55[.0] + * 1.6.58 16 10658 16.so.16.58[.0] * * Henceforth the source version will match the shared-library major and * minor numbers; the shared-library major version number will be used for @@ -274,7 +274,7 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.55" +#define PNG_LIBPNG_VER_STRING "1.6.58" #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" /* The versions of shared library builds should stay in sync, going forward */ @@ -285,7 +285,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 55 +#define PNG_LIBPNG_VER_RELEASE 58 /* This should be zero for a public release, or non-zero for a * development version. @@ -316,7 +316,7 @@ * From version 1.0.1 it is: * XXYYZZ, where XX=major, YY=minor, ZZ=release */ -#define PNG_LIBPNG_VER 10655 /* 1.6.55 */ +#define PNG_LIBPNG_VER 10658 /* 1.6.58 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -426,7 +426,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char *png_libpng_version_1_6_55; +typedef char *png_libpng_version_1_6_58; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -2341,7 +2341,7 @@ PNG_EXPORT(162, int, png_get_text, #endif /* Note while png_set_text() will accept a structure whose text, - * language, and translated keywords are NULL pointers, the structure + * language, and translated keywords are NULL pointers, the structure * returned by png_get_text will always contain regular * zero-terminated C strings. They might be empty strings but * they will never be NULL pointers. diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngconf.h b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngconf.h index 4508452419..3eda9d047b 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngconf.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngconf.h @@ -1,6 +1,6 @@ /* pngconf.h - machine-configurable file for libpng * - * libpng version 1.6.55 + * libpng version 1.6.58 * * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pnglibconf.h b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pnglibconf.h index 1e21b37b9e..435c752c2a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pnglibconf.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pnglibconf.h @@ -1,6 +1,6 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.55 */ +/* libpng version 1.6.58 */ /* Copyright (c) 2018-2026 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngpriv.h b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngpriv.h index f91666c700..a6c91ac2c7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngpriv.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngpriv.h @@ -957,7 +957,7 @@ * * At present these index values are not exported (not part of the public API) * so can be changed at will. For convenience the names are in lexical sort - * order but with the critical chunks at the start in the order of occurence in + * order but with the critical chunks at the start in the order of occurrence in * a PNG. * * PNG_INFO_ values do not exist for every one of these chunk handles; for @@ -2086,7 +2086,7 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed, * not valid it will be the index of a character in the supposed number. * * The format of a number is defined in the PNG extensions specification - * and this API is strictly conformant to that spec, not anyone elses! + * and this API is strictly conformant to that spec, not anyone else's! * * The format as a regular expression is: * diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngread.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngread.c index af2f44c9ca..24199689a7 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngread.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngread.c @@ -691,7 +691,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) png_read_finish_IDAT(png_ptr); #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Report invalid palette index; added at libng-1.5.10 */ + /* Report invalid palette index; added at libpng-1.5.10 */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_palette_max >= png_ptr->num_palette) png_benign_error(png_ptr, "Read palette index exceeding num_palette"); @@ -779,21 +779,19 @@ png_read_destroy(png_structrp png_ptr) png_ptr->quantize_index = NULL; #endif - if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) - { - png_zfree(png_ptr, png_ptr->palette); - png_ptr->palette = NULL; - } - png_ptr->free_me &= ~PNG_FREE_PLTE; + /* png_ptr->palette is always independently allocated (not aliased + * with info_ptr->palette), so free it unconditionally. + */ + png_free(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; #if defined(PNG_tRNS_SUPPORTED) || \ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) - { - png_free(png_ptr, png_ptr->trans_alpha); - png_ptr->trans_alpha = NULL; - } - png_ptr->free_me &= ~PNG_FREE_TRNS; + /* png_ptr->trans_alpha is always independently allocated (not aliased + * with info_ptr->trans_alpha), so free it unconditionally. + */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; #endif inflateEnd(&png_ptr->zstream); @@ -1256,7 +1254,7 @@ png_image_is_not_sRGB(png_const_structrp png_ptr) * png_struct::chromaticities always exists since the simplified API * requires rgb-to-gray. The mDCV, cICP and cHRM chunks may all set it to * a non-sRGB value, so it needs to be checked but **only** if one of - * those chunks occured in the file. + * those chunks occurred in the file. */ /* Highest priority: check to be safe. */ if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV)) @@ -2596,7 +2594,7 @@ png_image_read_colormap(png_voidp argument) { r = back_r; g = back_g; - b = back_g; + b = back_b; } /* Compare the newly-created color-map entry with the one the @@ -2874,9 +2872,9 @@ png_image_read_and_map(png_voidp argument) { png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; - /* Read read the libpng data into the temporary buffer. */ + /* Read the libpng data into the temporary buffer. */ png_read_row(png_ptr, inrow, NULL); /* Now process the row according to the processing option, note @@ -2887,7 +2885,7 @@ png_image_read_and_map(png_voidp argument) switch (proc) { case PNG_CMAP_GA: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { /* The data is always in the PNG order */ unsigned int gray = *inrow++; @@ -2916,7 +2914,7 @@ png_image_read_and_map(png_voidp argument) break; case PNG_CMAP_TRANS: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte gray = *inrow++; png_byte alpha = *inrow++; @@ -2933,7 +2931,7 @@ png_image_read_and_map(png_voidp argument) break; case PNG_CMAP_RGB: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); inrow += 3; @@ -2941,7 +2939,7 @@ png_image_read_and_map(png_voidp argument) break; case PNG_CMAP_RGB_ALPHA: - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { unsigned int alpha = inrow[3]; @@ -2978,10 +2976,10 @@ png_image_read_and_map(png_voidp argument) */ if (inrow[0] & 0x80) back_i += 9; /* red */ if (inrow[0] & 0x40) back_i += 9; - if (inrow[0] & 0x80) back_i += 3; /* green */ - if (inrow[0] & 0x40) back_i += 3; - if (inrow[0] & 0x80) back_i += 1; /* blue */ - if (inrow[0] & 0x40) back_i += 1; + if (inrow[1] & 0x80) back_i += 3; /* green */ + if (inrow[1] & 0x40) back_i += 3; + if (inrow[2] & 0x80) back_i += 1; /* blue */ + if (inrow[2] & 0x40) back_i += 1; *outrow = (png_byte)back_i; } @@ -3248,18 +3246,18 @@ png_image_read_composite(png_voidp argument) { png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow; - png_const_bytep end_row; + png_const_bytep row_end; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); outrow = png_voidcast(png_bytep, display->first_row); outrow += y * row_step; - end_row = outrow + width * channels; + row_end = outrow + width * channels; /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[channels]; @@ -3432,14 +3430,14 @@ png_image_read_background(png_voidp argument) png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[1]; @@ -3477,14 +3475,14 @@ png_image_read_background(png_voidp argument) png_bytep inrow = png_voidcast(png_bytep, display->local_row); png_bytep outrow = first_row + y * row_step; - png_const_bytep end_row = outrow + width; + png_const_bytep row_end = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_byte alpha = inrow[1]; @@ -3567,7 +3565,7 @@ png_image_read_background(png_voidp argument) { png_const_uint_16p inrow; png_uint_16p outrow = first_row + y * row_step; - png_uint_16p end_row = outrow + width * outchannels; + png_uint_16p row_end = outrow + width * outchannels; /* Read the row, which is packed: */ png_read_row(png_ptr, png_voidcast(png_bytep, @@ -3577,7 +3575,7 @@ png_image_read_background(png_voidp argument) /* Now do the pre-multiplication on each pixel in this row. */ outrow += startx; - for (; outrow < end_row; outrow += stepx) + for (; outrow < row_end; outrow += stepx) { png_uint_32 component = inrow[0]; png_uint_16 alpha = inrow[1]; @@ -4113,7 +4111,7 @@ png_image_finish_read(png_imagep image, png_const_colorp background, row_stride = (png_int_32)/*SAFE*/png_row_stride; if (row_stride < 0) - check = (png_uint_32)(-row_stride); + check = -(png_uint_32)row_stride; else check = (png_uint_32)row_stride; diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrtran.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrtran.c index 1fce9af121..0ac8df749e 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrtran.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrtran.c @@ -230,7 +230,7 @@ png_set_strip_alpha(png_structrp png_ptr) * * Terminology (assuming power law, "gamma", encodings): * "screen" gamma: a power law imposed by the output device when digital - * samples are converted to visible light output. The EOTF - volage to + * samples are converted to visible light output. The EOTF - voltage to * luminance on output. * * "file" gamma: a power law used to encode luminance levels from the input @@ -495,6 +495,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, if (png_rtran_ok(png_ptr, 0) == 0) return; + if (palette == NULL) + return; + png_ptr->transformations |= PNG_QUANTIZE; if (full_quantize == 0) @@ -811,7 +814,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, } if (png_ptr->palette == NULL) { - png_ptr->palette = palette; + /* Allocate an owned copy rather than aliasing the caller's pointer, + * so that png_read_destroy can free png_ptr->palette unconditionally. + */ + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + memcpy(png_ptr->palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); } png_ptr->num_palette = (png_uint_16)num_palette; @@ -1364,7 +1373,7 @@ png_resolve_file_gamma(png_const_structrp png_ptr) if (file_gamma != 0) return file_gamma; - /* If png_reciprocal oveflows it returns 0 which indicates to the caller that + /* If png_reciprocal overflows, it returns 0, indicating to the caller that * there is no usable file gamma. (The checks added to png_set_gamma and * png_set_alpha_mode should prevent a screen_gamma which would overflow.) */ @@ -2061,6 +2070,17 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_transform_info"); + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + info_ptr->palette != NULL && png_ptr->palette != NULL) + { + /* Sync info_ptr->palette with png_ptr->palette, which may + * have been modified by png_init_read_transformations + * (e.g. for gamma correction or background compositing). + */ + memcpy(info_ptr->palette, png_ptr->palette, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))); + } + #ifdef PNG_READ_EXPAND_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND) != 0) { @@ -2355,7 +2375,7 @@ png_do_unpack(png_row_infop row_info, png_bytep row) } row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_width * row_info->channels; + row_info->rowbytes = (size_t)row_width * row_info->channels; } } #endif @@ -2557,7 +2577,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; + row_info->rowbytes = (size_t)row_info->width * row_info->channels; } } #endif @@ -2585,7 +2605,7 @@ png_do_chop(png_row_infop row_info, png_bytep row) row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); - row_info->rowbytes = row_info->width * row_info->channels; + row_info->rowbytes = (size_t)row_info->width * row_info->channels; } } #endif @@ -2821,7 +2841,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = lo_filler; row_info->channels = 2; row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; + row_info->rowbytes = (size_t)row_width * 2; } else @@ -2836,7 +2856,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, } row_info->channels = 2; row_info->pixel_depth = 16; - row_info->rowbytes = row_width * 2; + row_info->rowbytes = (size_t)row_width * 2; } } @@ -2859,7 +2879,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = hi_filler; row_info->channels = 2; row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; + row_info->rowbytes = (size_t)row_width * 4; } else @@ -2876,7 +2896,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, } row_info->channels = 2; row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; + row_info->rowbytes = (size_t)row_width * 4; } } #endif @@ -2900,7 +2920,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = lo_filler; row_info->channels = 4; row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; + row_info->rowbytes = (size_t)row_width * 4; } else @@ -2917,7 +2937,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, } row_info->channels = 4; row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; + row_info->rowbytes = (size_t)row_width * 4; } } @@ -2944,7 +2964,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = hi_filler; row_info->channels = 4; row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; + row_info->rowbytes = (size_t)row_width * 8; } else @@ -2966,7 +2986,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, row_info->channels = 4; row_info->pixel_depth = 64; - row_info->rowbytes = row_width * 8; + row_info->rowbytes = (size_t)row_width * 8; } } #endif @@ -4460,7 +4480,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, } row_info->bit_depth = 8; row_info->pixel_depth = 32; - row_info->rowbytes = row_width * 4; + row_info->rowbytes = (size_t)row_width * 4; row_info->color_type = 6; row_info->channels = 4; } @@ -4468,7 +4488,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, else { sp = row + (size_t)row_width - 1; - dp = row + (size_t)(row_width * 3) - 1; + dp = row + (size_t)row_width * 3 - 1; i = 0; #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row, @@ -4487,7 +4507,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, row_info->bit_depth = 8; row_info->pixel_depth = 24; - row_info->rowbytes = row_width * 3; + row_info->rowbytes = (size_t)row_width * 3; row_info->color_type = 2; row_info->channels = 3; } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrutil.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrutil.c index a4eda54c8c..3a35fe9de2 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrutil.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngrutil.c @@ -436,7 +436,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) * be gained by using this when it is known *if* the zlib stream itself does * not record the number; however, this is an illusion: the original writer * of the PNG may have selected a lower window size, and we really must - * follow that because, for systems with with limited capabilities, we + * follow that because, for systems with limited capabilities, we * would otherwise reject the application's attempts to use a smaller window * size (zlib doesn't have an interface to say "this or lower"!). * @@ -1006,7 +1006,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) * in the case of an 8-bit display with a decoder which controls the palette. * * The alternative here is to ignore the error and store the palette anyway; - * destroying the tRNS will definately cause problems. + * destroying the tRNS will definitely cause problems. * * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and @@ -1053,19 +1053,6 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* A valid PLTE chunk has been read */ png_ptr->mode |= PNG_HAVE_PLTE; - /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to - * its own copy of the palette. This has the side effect that when - * png_start_row is called (this happens after any call to - * png_read_update_info) the info_ptr palette gets changed. This is - * extremely unexpected and confusing. - * - * REVIEW: there have been consistent bugs in the past about gamma and - * similar transforms to colour mapped images being useless because the - * modified palette cannot be accessed because of the above. - * - * CONSIDER: Fix this by not sharing the palette in this way. But does - * this completely fix the problem? - */ png_set_PLTE(png_ptr, info_ptr, palette, num); return handled_ok; } @@ -1267,7 +1254,7 @@ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* png_set_cHRM may complain about some of the values but this doesn't matter * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous) - * values. Ridiculousity will be checked if the values are used later. + * values. Ridiculosity will be checked if the values are used later. */ png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, xy.greenx, xy.greeny, xy.bluex, xy.bluey); @@ -1564,7 +1551,8 @@ static png_handle_result_code /* PRIVATE */ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep entry_start, buffer; + png_bytep buffer; + png_bytep entry_start; png_sPLT_t new_palette; png_sPLT_entryp pp; png_uint_32 data_length; @@ -1771,10 +1759,6 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) return handled_error; } - /* TODO: this is a horrible side effect in the palette case because the - * png_struct ends up with a pointer to the tRNS buffer owned by the - * png_info. Fix this. - */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); return handled_ok; @@ -2033,7 +2017,7 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) return handled_error; /* PNGv3: the code used to check the byte order mark at the start for MM or - * II, however PNGv3 states that the the first 4 bytes should be checked. + * II, however PNGv3 states that the first 4 bytes should be checked. * The caller ensures that there are four bytes available. */ { @@ -2155,9 +2139,13 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) static png_handle_result_code /* PRIVATE */ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { + png_bytep buffer; + png_bytep buf; + png_bytep endptr; png_int_32 X0, X1; - png_byte type, nparams; - png_bytep buffer, buf, units, endptr; + png_byte type; + png_byte nparams; + png_byte *units; png_charpp params; int i; @@ -3011,7 +2999,7 @@ static const struct png_uint_32 max_length :12; /* Length min, max in bytes */ png_uint_32 min_length :8; /* Length errors on critical chunks have special handling to preserve the - * existing behaviour in libpng 1.6. Anciallary chunks are checked below + * existing behaviour in libpng 1.6. Ancillary chunks are checked below * and produce a 'benign' error. */ png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */ @@ -3019,7 +3007,7 @@ static const struct /* NOTE: PLTE, tRNS and bKGD require special handling which depends on * the colour type of the base image. */ - png_uint_32 multiple :1; /* Multiple occurences permitted */ + png_uint_32 multiple :1; /* Multiple occurrences permitted */ /* This is enabled for PLTE because PLTE may, in practice, be optional */ } read_chunks[PNG_INDEX_unknown] = @@ -3053,7 +3041,7 @@ read_chunks[PNG_INDEX_unknown] = # define CDIHDR 13U, 13U, hIHDR, 0, 0 # define CDPLTE NoCheck, 0U, 0, hIHDR, 1 /* PLTE errors are only critical for colour-map images, consequently the - * hander does all the checks. + * handler does all the checks. */ # define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1 # define CDIEND NoCheck, 0U, 0, aIDAT, 0 diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngset.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngset.c index 3e63c2724e..513c51eb4a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngset.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngset.c @@ -1,6 +1,6 @@ /* pngset.c - storage of image information into info struct * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -333,7 +333,8 @@ png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(1, "in %s storage function", "eXIf"); if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_eXIf) != 0) + (png_ptr->mode & PNG_WROTE_eXIf) != 0 || + exif == NULL) return; new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif)); @@ -384,11 +385,12 @@ void PNGAPI png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist) { + png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH]; int i; png_debug1(1, "in %s storage function", "hIST"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || hist == NULL) return; if (info_ptr->num_palette == 0 || info_ptr->num_palette @@ -400,6 +402,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, return; } + /* Snapshot the caller's hist before freeing, in case it points to + * info_ptr->hist (getter-to-setter aliasing). + */ + memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette * + (sizeof (png_uint_16))); + hist = safe_hist; + png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in @@ -741,7 +750,7 @@ void PNGAPI png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { - + png_color safe_palette[PNG_MAX_PALETTE_LENGTH]; png_uint_32 max_palette_length; png_debug1(1, "in %s storage function", "PLTE"); @@ -775,28 +784,47 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_error(png_ptr, "Invalid palette"); } - /* It may not actually be necessary to set png_ptr->palette here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: the above statement appears to be incorrect; something has to set - * the palette inside png_struct on read. + /* Snapshot the caller's palette before freeing, in case it points to + * info_ptr->palette (getter-to-setter aliasing). */ + if (num_palette > 0) + memcpy(safe_palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); + + palette = safe_palette; + png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead * of num_palette entries, in case of an invalid PNG file or incorrect * call to png_set_PLTE() with too-large sample values. + * + * Allocate independent buffers for info_ptr and png_ptr so that the + * lifetime of png_ptr->palette is decoupled from the lifetime of + * info_ptr->palette. Previously, these two pointers were aliased, + * which caused a use-after-free vulnerability if png_free_data freed + * info_ptr->palette while png_ptr->palette was still in use by the + * row transform functions (e.g. png_do_expand_palette). + * + * Both buffers are allocated with png_calloc to zero-fill, because + * the ARM NEON palette riffle reads all 256 entries unconditionally, + * regardless of num_palette. */ + png_free(png_ptr, png_ptr->palette); png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); + png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette; if (num_palette > 0) + { + memcpy(info_ptr->palette, palette, (unsigned int)num_palette * + (sizeof (png_color))); memcpy(png_ptr->palette, palette, (unsigned int)num_palette * (sizeof (png_color))); + } - info_ptr->palette = png_ptr->palette; - info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; info_ptr->free_me |= PNG_FREE_PLTE; info_ptr->valid |= PNG_INFO_PLTE; } @@ -926,6 +954,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text) { int i; + png_textp old_text = NULL; png_debug1(1, "in text storage function, chunk typeid = 0x%lx", png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name); @@ -973,7 +1002,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, return 1; } - png_free(png_ptr, info_ptr->text); + /* Defer freeing the old array until after the copy loop below, + * in case text_ptr aliases info_ptr->text (getter-to-setter). + */ + old_text = info_ptr->text; info_ptr->text = new_text; info_ptr->free_me |= PNG_FREE_TEXT; @@ -1058,6 +1090,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, { png_chunk_report(png_ptr, "text chunk: out of memory", PNG_CHUNK_WRITE_ERROR); + png_free(png_ptr, old_text); return 1; } @@ -1111,6 +1144,8 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } + png_free(png_ptr, old_text); + return 0; } #endif @@ -1154,28 +1189,50 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, if (trans_alpha != NULL) { - /* It may not actually be necessary to set png_ptr->trans_alpha here; - * we do it for backward compatibility with the way the png_handle_tRNS - * function used to do the allocation. - * - * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively - * relies on png_set_tRNS storing the information in png_struct - * (otherwise it won't be there for the code in pngrtran.c). + /* Snapshot the caller's trans_alpha before freeing, in case it + * points to info_ptr->trans_alpha (getter-to-setter aliasing). */ + png_byte safe_trans[PNG_MAX_PALETTE_LENGTH]; + + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + memcpy(safe_trans, trans_alpha, (size_t)num_trans); + + trans_alpha = safe_trans; png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) { - /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + /* Allocate info_ptr's copy of the transparency data. + * Initialize all entries to fully opaque (0xff), then overwrite + * the first num_trans entries with the actual values. + */ info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH); memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); - info_ptr->free_me |= PNG_FREE_TRNS; info_ptr->valid |= PNG_INFO_tRNS; + + /* Allocate an independent copy for png_struct, so that the + * lifetime of png_ptr->trans_alpha is decoupled from the + * lifetime of info_ptr->trans_alpha. Previously these two + * pointers were aliased, which caused a use-after-free if + * png_free_data freed info_ptr->trans_alpha while + * png_ptr->trans_alpha was still in use by the row transform + * functions (e.g. png_do_expand_palette). + */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); + memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH); + memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans); + } + else + { + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; } - png_ptr->trans_alpha = info_ptr->trans_alpha; } if (trans_color != NULL) @@ -1226,6 +1283,7 @@ png_set_sPLT(png_const_structrp png_ptr, */ { png_sPLT_tp np; + png_sPLT_tp old_spalettes; png_debug1(1, "in %s storage function", "sPLT"); @@ -1246,7 +1304,10 @@ png_set_sPLT(png_const_structrp png_ptr, return; } - png_free(png_ptr, info_ptr->splt_palettes); + /* Defer freeing the old array until after the copy loop below, + * in case entries aliases info_ptr->splt_palettes (getter-to-setter). + */ + old_spalettes = info_ptr->splt_palettes; info_ptr->splt_palettes = np; info_ptr->free_me |= PNG_FREE_SPLT; @@ -1310,6 +1371,8 @@ png_set_sPLT(png_const_structrp png_ptr, } while (--nentries); + png_free(png_ptr, old_spalettes); + if (nentries > 0) png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); } @@ -1358,6 +1421,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; + png_unknown_chunkp old_unknowns; if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || unknowns == NULL) @@ -1404,7 +1468,10 @@ png_set_unknown_chunks(png_const_structrp png_ptr, return; } - png_free(png_ptr, info_ptr->unknown_chunks); + /* Defer freeing the old array until after the copy loop below, + * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter). + */ + old_unknowns = info_ptr->unknown_chunks; info_ptr->unknown_chunks = np; /* safe because it is initialized */ info_ptr->free_me |= PNG_FREE_UNKN; @@ -1450,6 +1517,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr, ++np; ++(info_ptr->unknown_chunks_num); } + + png_free(png_ptr, old_unknowns); } void PNGAPI @@ -1873,7 +1942,7 @@ png_set_benign_errors(png_structrp png_ptr, int allowed) #endif /* BENIGN_ERRORS */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Whether to report invalid palette index; added at libng-1.5.10. + /* Whether to report invalid palette index; added at libpng-1.5.10. * It is possible for an indexed (color-type==3) PNG file to contain * pixels with invalid (out-of-range) indexes if the PLTE chunk has * fewer entries than the image's bit-depth would allow. We recover diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngstruct.h b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngstruct.h index fe5fa04155..5cd7ddb45a 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngstruct.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngstruct.h @@ -1,6 +1,6 @@ /* pngstruct.h - internal structures for libpng * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -106,7 +106,7 @@ typedef enum * TODO: C23: convert these macros to C23 inlines (which are static). */ #define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i))) - /* The flag coresponding to the given png_index enum value. This is defined + /* The flag corresponding to the given png_index enum value. This is defined * for png_unknown as well (until it reaches the value 32) but this should * not be relied on. */ @@ -115,7 +115,7 @@ typedef enum (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0) /* The chunk has been recorded in png_struct */ -#define png_file_add_chunk(pnt_ptr, i)\ +#define png_file_add_chunk(png_ptr, i)\ ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i))) /* Record the chunk in the png_struct */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngtrans.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngtrans.c index 19f5c641b2..32a5fd3c0f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngtrans.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngtrans.c @@ -1,6 +1,6 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Copyright (c) 2018-2024 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -84,9 +84,38 @@ png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) { png_debug(1, "in png_set_shift"); - if (png_ptr == NULL) + if (png_ptr == NULL || true_bits == NULL) return; + /* Check the shift values before passing them on to png_do_shift. */ + { + png_byte bit_depth = png_ptr->bit_depth; + int invalid = 0; + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + if (true_bits->red == 0 || true_bits->red > bit_depth || + true_bits->green == 0 || true_bits->green > bit_depth || + true_bits->blue == 0 || true_bits->blue > bit_depth) + invalid = 1; + } + else + { + if (true_bits->gray == 0 || true_bits->gray > bit_depth) + invalid = 1; + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 && + (true_bits->alpha == 0 || true_bits->alpha > bit_depth)) + invalid = 1; + + if (invalid) + { + png_app_error(png_ptr, "png_set_shift: invalid shift values"); + return; + } + } + png_ptr->transformations |= PNG_SHIFT; png_ptr->shift = *true_bits; } @@ -457,10 +486,9 @@ png_do_packswap(png_row_infop row_info, png_bytep row) if (row_info->bit_depth < 8) { + png_const_bytep table; png_bytep rp; - png_const_bytep end, table; - - end = row + row_info->rowbytes; + png_bytep row_end = row + row_info->rowbytes; if (row_info->bit_depth == 1) table = onebppswaptable; @@ -474,7 +502,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row) else return; - for (rp = row; rp < end; rp++) + for (rp = row; rp < row_end; rp++) *rp = table[*rp]; } } diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwrite.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwrite.c index 362a8c3e16..2c95eb66ca 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwrite.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwrite.c @@ -159,7 +159,7 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) * them. * * PNG v3: Chunks mDCV and cLLI provide ancillary information for the - * interpretation of the colourspace chunkgs but do not require support for + * interpretation of the colourspace chunks but do not require support for * those chunks so are outside the "COLORSPACE" check but before the write of * the colourspace chunks themselves. */ @@ -1010,6 +1010,16 @@ png_write_destroy(png_structrp png_ptr) png_ptr->chunk_list = NULL; #endif +#if defined(PNG_tRNS_SUPPORTED) + /* Free the independent copy of trans_alpha owned by png_struct. */ + png_free(png_ptr, png_ptr->trans_alpha); + png_ptr->trans_alpha = NULL; +#endif + + /* Free the independent copy of the palette owned by png_struct. */ + png_free(png_ptr, png_ptr->palette); + png_ptr->palette = NULL; + /* The error handling and memory handling information is left intact at this * point: the jmp_buf may still have to be freed. See png_destroy_png_struct * for how this happens. @@ -2020,7 +2030,7 @@ png_image_write_main(png_voidp argument) display->row_stride = (png_int_32)/*SAFE*/png_row_stride; if (display->row_stride < 0) - check = (png_uint_32)(-display->row_stride); + check = -(png_uint_32)display->row_stride; else check = (png_uint_32)display->row_stride; @@ -2219,7 +2229,7 @@ png_image_write_main(png_voidp argument) static void (PNGCBAPI -image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size) +image_memory_write)(png_structp png_ptr, png_bytep data, size_t size) { png_image_write_control *display = png_voidcast(png_image_write_control*, png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwutil.c b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwutil.c index b4b845a7b6..e16c387c20 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwutil.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/pngwutil.c @@ -1,6 +1,6 @@ /* pngwutil.c - utilities to write a PNG file * - * Copyright (c) 2018-2025 Cosmin Truta + * Copyright (c) 2018-2026 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -898,7 +898,6 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_debug1(3, "num_palette = %d", png_ptr->num_palette); png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); -#ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) { @@ -908,21 +907,6 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_write_chunk_data(png_ptr, buf, 3); } -#else - /* This is a little slower but some buggy compilers need to do this - * instead - */ - pal_ptr=palette; - - for (i = 0; i < num_pal; i++) - { - buf[0] = pal_ptr[i].red; - buf[1] = pal_ptr[i].green; - buf[2] = pal_ptr[i].blue; - png_write_chunk_data(png_ptr, buf, 3); - } - -#endif png_write_chunk_end(png_ptr); png_ptr->mode |= PNG_HAVE_PLTE; } @@ -1201,9 +1185,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) size_t entry_size = (spalette->depth == 8 ? 6 : 10); size_t palette_size = entry_size * (size_t)spalette->nentries; png_sPLT_entryp ep; -#ifndef PNG_POINTER_INDEXING_SUPPORTED - int i; -#endif png_debug(1, "in png_write_sPLT"); @@ -1221,7 +1202,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) png_write_chunk_data(png_ptr, &spalette->depth, 1); /* Loop through each palette entry, writing appropriately */ -#ifdef PNG_POINTER_INDEXING_SUPPORTED for (ep = spalette->entries; epentries + spalette->nentries; ep++) { if (spalette->depth == 8) @@ -1244,31 +1224,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) png_write_chunk_data(png_ptr, entrybuf, entry_size); } -#else - ep=spalette->entries; - for (i = 0; i>spalette->nentries; i++) - { - if (spalette->depth == 8) - { - entrybuf[0] = (png_byte)ep[i].red; - entrybuf[1] = (png_byte)ep[i].green; - entrybuf[2] = (png_byte)ep[i].blue; - entrybuf[3] = (png_byte)ep[i].alpha; - png_save_uint_16(entrybuf + 4, ep[i].frequency); - } - - else - { - png_save_uint_16(entrybuf + 0, ep[i].red); - png_save_uint_16(entrybuf + 2, ep[i].green); - png_save_uint_16(entrybuf + 4, ep[i].blue); - png_save_uint_16(entrybuf + 6, ep[i].alpha); - png_save_uint_16(entrybuf + 8, ep[i].frequency); - } - - png_write_chunk_data(png_ptr, entrybuf, entry_size); - } -#endif png_write_chunk_end(png_ptr); } @@ -1738,7 +1693,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, } new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; - ++key_len; /* for the keywod separator */ + ++key_len; /* for the keyword separator */ /* We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/qt_attribution.json b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/qt_attribution.json index af5963c0e5..1c93293621 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/libpng/qt_attribution.json +++ b/local/recipes/qt/qtbase/source/src/3rdparty/libpng/qt_attribution.json @@ -7,8 +7,8 @@ "Description": "libpng is the official PNG reference library.", "Homepage": "http://www.libpng.org/pub/png/libpng.html", - "Version": "1.6.55", - "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.55.tar.xz", + "Version": "1.6.58", + "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.58.tar.xz", "PURL": "pkg:github/pnggroup/libpng@v$", "CPE": "cpe:2.3:a:libpng:libpng:$:*:*:*:*:*:*:*", diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/CMakeLists.txt index 3f4a467778..779e00ad4f 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/CMakeLists.txt @@ -29,6 +29,7 @@ qt_internal_add_3rdparty_library(BundledPcre2 src/pcre2_maketables.c src/pcre2_match.c src/pcre2_match_data.c + src/pcre2_match_next.c src/pcre2_newline.c src/pcre2_ord2utf.c src/pcre2_pattern_info.c diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/import_from_pcre2_tarball.sh b/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/import_from_pcre2_tarball.sh index 3a8c29bf01..31142b321b 100755 --- a/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/import_from_pcre2_tarball.sh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/pcre2/import_from_pcre2_tarball.sh @@ -68,6 +68,7 @@ FILES=" src/pcre2_maketables.c src/pcre2_match.c src/pcre2_match_data.c + src/pcre2_match_next.c src/pcre2_newline.c src/pcre2_ord2utf.c src/pcre2_pattern_info.c diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/sha3/brg_endian.h.orig b/local/recipes/qt/qtbase/source/src/3rdparty/sha3/brg_endian.h.orig new file mode 100644 index 0000000000..0baac93dc9 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/3rdparty/sha3/brg_endian.h.orig @@ -0,0 +1,139 @@ +/* +--------------------------------------------------------------------------- +Copyright (c) 1998-2013, Brian Gladman, Worcester, UK. All rights reserved. + +The redistribution and use of this software (with or without changes) +is allowed without the payment of fees or royalties provided that: + + source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation. + +This software is provided 'as is' with no explicit or implied warranties +in respect of its operation, including, but not limited to, correctness +and fitness for purpose. +--------------------------------------------------------------------------- +Issue Date: 20/12/2007 +Changes for ARM 9/9/2010 [Downstream relative to Gladman's GitHub, upstream to Qt] +*/ + +#ifndef _BRG_ENDIAN_H +#define _BRG_ENDIAN_H + +#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ +#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ + +/* This is needed when using clang with MSVC to avoid including */ +/* endian.h and byteswap.h which are not present on Windows */ +#if defined( _MSC_VER ) && defined( __clang__ ) +# undef __GNUC__ +#endif + +/* Include files where endian defines and byteswap functions may reside */ +#if defined( __sun ) +# include +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) && !defined(Q_OS_QNX) +# include +# if !defined( __BEOS__ ) && !defined(Q_OS_RTEMS) && !defined(Q_OS_VXWORKS) +# include +# endif +# endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif defined(__arm__) +# ifdef __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# else +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif 1 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 129 or 131 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/qt_attribution.json b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/qt_attribution.json index 917e31c3d1..1b7faa1236 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/qt_attribution.json +++ b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/qt_attribution.json @@ -7,10 +7,10 @@ "Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.", "Homepage": "https://www.sqlite.org/", - "Version": "3.51.2", + "Version": "3.53.0", "PURL": "pkg:github/sqlite/sqlite@version-$", "CPE": "cpe:2.3:a:sqlite:sqlite:$:*:*:*:*:*:*:*", - "DownloadLocation": "https://www.sqlite.org/2026/sqlite-amalgamation-3510200.zip", + "DownloadLocation": "https://www.sqlite.org/2026/sqlite-amalgamation-3530000.zip", "License": "SQLite Blessing", "LicenseId": "blessing", "Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed." diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.c b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.c index b44fb754da..91db04a9ec 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.c +++ b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.51.2. By combining all the individual C code files into this +** version 3.53.0. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** b270f8339eb13b504d0b2ba154ebca966b7d with changes in files: +** 4525003a53a7fc63ca75c59b22c79608659c with changes in files: ** ** */ @@ -467,12 +467,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.51.2" -#define SQLITE_VERSION_NUMBER 3051002 -#define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075" -#define SQLITE_SCM_BRANCH "branch-3.51" -#define SQLITE_SCM_TAGS "release version-3.51.2" -#define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z" +#define SQLITE_VERSION "3.53.0" +#define SQLITE_VERSION_NUMBER 3053000 +#define SQLITE_SOURCE_ID "2026-04-09 11:41:38 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b" +#define SQLITE_SCM_BRANCH "trunk" +#define SQLITE_SCM_TAGS "release major-release version-3.53.0" +#define SQLITE_SCM_DATETIME "2026-04-09T11:41:38.498Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -899,7 +899,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal only */ /* ** CAPI3REF: Flags For File Open Operations @@ -1611,6 +1611,12 @@ struct sqlite3_io_methods { #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO +/* reserved file-control numbers: +** 101 +** 102 +** 103 +*/ + /* ** CAPI3REF: Mutex Handle @@ -1811,7 +1817,7 @@ typedef const char *sqlite3_filename; ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can @@ -2032,7 +2038,8 @@ SQLITE_API int sqlite3_os_end(void); ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** configuration option, then the sqlite3_config() call will +** return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** @@ -2598,9 +2605,10 @@ struct sqlite3_mem_methods { ** is less than 8. The "sz" argument should be a multiple of 8 less than ** 65536. If "sz" does not meet this constraint, it is reduced in size until ** it does. -**

  • The third argument ("cnt") is the number of slots. Lookaside is disabled -** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so -** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +**

  • The third argument ("cnt") is the number of slots. +** Lookaside is disabled if "cnt"is less than 1. +* The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" ** parameter is usually chosen so that the product of "sz" and "cnt" is less ** than 1,000,000. ** @@ -2888,12 +2896,15 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **

    SQLITE_DBCONFIG_STMT_SCANSTATUS
    **
    The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default.

    This option takes two arguments: an integer and a pointer to +** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears +** a flag that enables collection of run-time performance statistics +** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle] +** columns of the [bytecode virtual table]. +** For statistics to be collected, the flag must be set on +** the database handle both when the SQL statement is +** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped]. +** The flag is set (collection of statistics is enabled) by default. +**

    This option takes two arguments: an integer and a pointer to ** an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after @@ -2966,16 +2977,34 @@ struct sqlite3_mem_methods { ** comments are allowed in SQL text after processing the first argument. **

    ** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
    SQLITE_DBCONFIG_FP_DIGITS
    +**
    The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** unaltered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

    +** ** ** ** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    ** **

    Most of the SQLITE_DBCONFIG options take two arguments, so that the ** overall call to [sqlite3_db_config()] has a total of four parameters. -** The first argument (the third parameter to sqlite3_db_config()) is an integer. -** The second argument is a pointer to an integer. If the first argument is 1, -** then the option becomes enabled. If the first integer argument is 0, then the -** option is disabled. If the first argument is -1, then the option setting +** The first argument (the third parameter to sqlite3_db_config()) is +** an integer. +** The second argument is a pointer to an integer. If the first argument is 1, +** then the option becomes enabled. If the first integer argument is 0, +** then the option is disabled. +** If the first argument is -1, then the option setting ** is unchanged. The second argument, the pointer to an integer, may be NULL. ** If the second argument is not NULL, then a value of 0 or 1 is written into ** the integer to which the second argument points, depending on whether the @@ -2983,9 +3012,10 @@ struct sqlite3_mem_methods { ** the first argument. ** **

    While most SQLITE_DBCONFIG options use the argument format -** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME] -** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the -** documentation of those exceptional options for details. +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ @@ -3010,7 +3040,8 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -4492,6 +4523,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); **

  • sqlite3_errmsg() **
  • sqlite3_errmsg16() **
  • sqlite3_error_offset() +**
  • sqlite3_db_handle() ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language @@ -4538,7 +4570,7 @@ SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* -** CAPI3REF: Set Error Codes And Message +** CAPI3REF: Set Error Code And Message ** METHOD: sqlite3 ** ** Set the error code of the database handle passed as the first argument @@ -4657,6 +4689,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
    SQLITE_LIMIT_EXPR_DEPTH
    **
    The maximum depth of the parse tree on any expression.
    )^ ** +** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
    SQLITE_LIMIT_PARSER_DEPTH
    +**
    The maximum depth of the LALR(1) parser stack used to analyze +** input SQL statements.
    )^ +** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
    SQLITE_LIMIT_COMPOUND_SELECT
    **
    The maximum number of terms in a compound SELECT statement.
    )^ ** @@ -4701,6 +4737,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_PARSER_DEPTH 12 /* ** CAPI3REF: Prepare Flags @@ -4745,12 +4782,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** fails, the sqlite3_prepare_v3() call returns the same error indications ** with or without this flag; it just omits the call to [sqlite3_log()] that ** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
    SQLITE_PREPARE_FROM_DDL
    +**
    The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 #define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement @@ -4764,8 +4818,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes +** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided @@ -5170,8 +5225,8 @@ typedef struct sqlite3_context sqlite3_context; ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. +** either UTF8 if the sixth parameter is SQLITE_UTF8 or SQLITE_UTF8_ZT, +** or UTF16 otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) @@ -5217,10 +5272,15 @@ typedef struct sqlite3_context sqlite3_context; ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the +** ^The sixth argument (the E argument) +** to sqlite3_bind_text64(S,K,Z,N,D,E) must be one of +** [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE] to specify the encoding of the text in the +** third parameter, Z. The special value [SQLITE_UTF8_ZT] means that the +** string argument is both UTF-8 encoded and is zero-terminated. In other +** words, SQLITE_UTF8_ZT means that the Z array is allocated to hold at +** least N+1 bytes and that the Z[N] byte is zero. If +** the E argument to sqlite3_bind_text64(S,K,Z,N,D,E) is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. @@ -6087,6 +6147,52 @@ SQLITE_API int sqlite3_create_window_function( ** ** These constants define integer codes that represent the various ** text encodings supported by SQLite. +** +**
    +** [[SQLITE_UTF8]]
    SQLITE_UTF8
    Text is encoding as UTF-8
    +** +** [[SQLITE_UTF16LE]]
    SQLITE_UTF16LE
    Text is encoding as UTF-16 +** with each code point being expressed "little endian" - the least significant +** byte first. This is the usual encoding, for example on Windows.
    +** +** [[SQLITE_UTF16BE]]
    SQLITE_UTF16BE
    Text is encoding as UTF-16 +** with each code point being expressed "big endian" - the most significant +** byte first. This encoding is less common, but is still sometimes seen, +** specially on older systems. +** +** [[SQLITE_UTF16]]
    SQLITE_UTF16
    Text is encoding as UTF-16 +** with each code point being expressed either little endian or as big +** endian, according to the native endianness of the host computer. +** +** [[SQLITE_ANY]]
    SQLITE_ANY
    This encoding value may only be used +** to declare the preferred text for [application-defined SQL functions] +** created using [sqlite3_create_function()] and similar. If the preferred +** encoding (the 4th parameter to sqlite3_create_function() - the eTextRep +** parameter) is SQLITE_ANY, that indicates that the function does not have +** a preference regarding the text encoding of its parameters and can take +** any text encoding that the SQLite core find convenient to supply. This +** option is deprecated. Please do not use it in new applications. +** +** [[SQLITE_UTF16_ALIGNED]]
    SQLITE_UTF16_ALIGNED
    This encoding +** value may be used as the 3rd parameter (the eTextRep parameter) to +** [sqlite3_create_collation()] and similar. This encoding value means +** that the application-defined collating sequence created expects its +** input strings to be in UTF16 in native byte order, and that the start +** of the strings must be aligned to a 2-byte boundary. +** +** [[SQLITE_UTF8_ZT]]
    SQLITE_UTF8_ZT
    This option can only be +** used to specify the text encoding to strings input to +** [sqlite3_result_text64()] and [sqlite3_bind_text64()]. +** The SQLITE_UTF8_ZT encoding means that the input string (call it "z") +** is UTF-8 encoded and that it is zero-terminated. If the length parameter +** (call it "n") is non-negative, this encoding option means that the caller +** guarantees that z array contains at least n+1 bytes and that the z[n] +** byte has a value of zero. +** This option gives the same output as SQLITE_UTF8, but can be more efficient +** by avoiding the need to make a copy of the input string, in some cases. +** However, if z is allocated to hold fewer than n+1 bytes or if the +** z[n] byte is not zero, undefined behavior may result. +**
    */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ @@ -6094,6 +6200,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8_ZT 16 /* Zero-terminated UTF8 */ /* ** CAPI3REF: Function Flags @@ -6328,26 +6435,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
      -**
    • sqlite3_value_blob() -**
    • sqlite3_value_text() -**
    • sqlite3_value_text16() -**
    • sqlite3_value_text16le() -**
    • sqlite3_value_text16be() -**
    • sqlite3_value_bytes() -**
    • sqlite3_value_bytes16() -**
    -** +** fail if an out-of-memory error occurs while trying to do a +** UTF8→UTF16 or UTF16→UTF8 conversion. ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect +** If the input sqlite3_value was not obtained from [sqlite3_value_dup()], +** then valid SQL NULL returns can also be distinguished from +** out-of-memory errors after extracting the value +** by invoking the [sqlite3_errcode()] immediately after the suspicious ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. +** If the input sqlite3_value was obtained from sqlite3_value_dup() then +** it is disconnected from the database connection and so sqlite3_errcode() +** will not work. +** In that case, the only way to distinguish an out-of-memory +** condition from a true SQL NULL is to invoke sqlite3_value_type() on the +** input to see if it is NULL prior to trying to extract the value. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -6374,7 +6477,8 @@ SQLITE_API int sqlite3_value_frombind(sqlite3_value*); ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], +** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], +** [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). @@ -6505,17 +6609,17 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular -** expression can be stored as auxiliary data associated with the pattern string. -** Then as long as the pattern string remains the same, +** expression can be stored as auxiliary data associated with the pattern +** string. Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no auxiliary data -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary +** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the +** Nth argument value to the application-defined function. ^N is zero +** for the left-most function argument. ^If there is no auxiliary data +** associated with the function argument, the sqlite3_get_auxdata(C,N) +** interface returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent @@ -6599,10 +6703,14 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a -** single database connection. However, the implementation is optimized -** for the case of having only one or two different client data names. -** Applications and wrapper libraries are discouraged from using more than -** one client data name each. +** single database connection. However, the current implementation stores +** the content on a linked list. Insert and retrieval performance will +** be proportional to the number of entries. The design use case, and +** the use case for which the implementation is optimized, is +** that an application will store only small number of client data names, +** typically just one or two. This interface is not intended to be a +** generalized key/value store for thousands or millions of keys. It +** will work for that, but performance might be disappointing. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought @@ -6710,10 +6818,14 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an +** ^The sqlite3_result_text64(C,Z,N,D,E) interface sets the return value of an ** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** specified the E parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that +** the result text is both UTF-8 and zero-terminated. In other words, +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that +** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces @@ -6800,7 +6912,7 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char *z, sqlite3_uint64 n, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); @@ -7739,7 +7851,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. +** with various operating-system specific filename extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. @@ -7747,10 +7859,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where -** X consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** If that does not work, it tries names of the form "sqlite3_X_init" +** where X consists of the lower-case equivalent of all ASCII alphabetic +** characters or all ASCII alphanumeric characters in the filename from +** the last "/" to the first following "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the @@ -7824,7 +7936,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); **
     **    int xEntryPoint(
     **      sqlite3 *db,
    -**      const char **pzErrMsg,
    +**      char **pzErrMsg,
     **      const struct sqlite3_api_routines *pThunk
     **    );
     ** 
    )^ @@ -8574,13 +8686,6 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() @@ -8935,6 +9040,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ +#define SQLITE_TESTCTRL_ATOF 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* @@ -9043,17 +9149,22 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. +** +** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object +** X and the string content it contains. Calling sqlite3_str_free(X) is +** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); +SQLITE_API void sqlite3_str_free(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. +** These interfaces add or remove content to an sqlite3_str object +** previously obtained from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] @@ -9076,6 +9187,10 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** +** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string +** under construction to be N bytes or less. This routine is a no-op if +** N is negative or if the string is already N bytes or smaller in size. +** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. @@ -9086,6 +9201,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); +SQLITE_API void sqlite3_str_truncate(sqlite3_str*,int N); /* ** CAPI3REF: Status Of A Dynamic String @@ -10616,7 +10732,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** sqlite3_vtab_distinct() return value ** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent +** Rows with the same value in all aOrderBy columns are +** adjacent ** Duplicates over all colUsed columns may be omitted ** 0yesyesno ** 1noyesno @@ -10625,8 +10742,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** ** ^For the purposes of comparing virtual table output values to see if the -** values are the same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" +** values are the same value for sorting purposes, two NULL values are +** considered to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements @@ -10919,9 +11036,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX +** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If +** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API @@ -10935,7 +11052,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** -** See also: [sqlite3_stmt_scanstatus_reset()] +** See also: [sqlite3_stmt_scanstatus_reset()] and the +** [nexec and ncycle] columns of the [bytecode virtual table]. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -11477,19 +11595,42 @@ SQLITE_API int sqlite3_deserialize( /* ** CAPI3REF: Bind array values to the CARRAY table-valued function ** -** The sqlite3_carray_bind(S,I,P,N,F,X) interface binds an array value to -** one of the first argument of the [carray() table-valued function]. The -** S parameter is a pointer to the [prepared statement] that uses the carray() -** functions. I is the parameter index to be bound. P is a pointer to the -** array to be bound, and N is the number of eements in the array. The -** F argument is one of constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], -** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], or [SQLITE_CARRAY_BLOB] to -** indicate the datatype of the array being bound. The X argument is not a -** NULL pointer, then SQLite will invoke the function X on the P parameter -** after it has finished using P, even if the call to -** sqlite3_carray_bind() fails. The special-case finalizer -** SQLITE_TRANSIENT has no effect here. +** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to +** parameter that is the first argument of the [carray() table-valued function]. +** The S parameter is a pointer to the [prepared statement] that uses the +** carray() functions. I is the parameter index to be bound. I must be the +** index of the parameter that is the first argument to the carray() +** table-valued function. P is a pointer to the array to be bound, and N +** is the number of elements in the array. The F argument is one of +** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], +** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], +** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P. +** +** If the X argument is not a NULL pointer or one of the special +** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke +** the function X with argument D when it is finished using the data in P. +** The call to X(D) is a destructor for the array P. The destructor X(D) +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X +** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes +** that the data static and the destructor is never invoked. If the X +** parameter is the special-case value [SQLITE_TRANSIENT], then +** sqlite3_carray_bind_v2() makes its own private copy of the data prior +** to returning and never invokes the destructor X. +** +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() +** with a D parameter set to P. In other words, +** sqlite3_carray_bind(S,I,P,N,F,X) is same as +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). */ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*), /* Destructor for aData */ + void *pDel /* Optional argument to xDel() */ +); SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, /* Statement to be bound */ int i, /* Parameter index */ @@ -13520,6 +13661,232 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passed as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +SQLITE_API int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may be passed as the 2nd parameter to +** sqlite3changegroup_config(). +** +**
    SQLITE_CHANGEGROUP_CONFIG_PATCHSET
    +** A changegroup object generates either a changeset or patchset. Usually, +** this is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is a no-op, not an error, if the changegroup is not +** configured because it has already started accumulating changes. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + +/* +** CAPI3REF: Begin adding a change to a changegroup +** +** This API is used, in concert with other sqlite3changegroup_change_xxx() +** APIs, to add changes to a changegroup object one at a time. To add a +** single change, the caller must: +** +** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of +** change (INSERT, UPDATE or DELETE), the affected table and whether +** or not the change should be marked as indirect. +** +** 2. Invoke sqlite3changegroup_change_int64() or one of the other four +** value functions - _null(), _double(), _text() or _blob() - one or +** more times to specify old.* and new.* values for the change being +** constructed. +** +** 3. Invoke sqlite3changegroup_change_finish() to either finish adding +** the change to the group, or to discard the change altogether. +** +** The first argument to this function must be a pointer to the existing +** changegroup object that the change will be added to. The second argument +** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the +** name of the table that the change affects, and the fourth is a boolean +** flag specifying whether the change should be marked as "indirect" (if +** bIndirect is non-zero) or not indirect (if bIndirect is zero). +** +** Following a successful call to this function, this function may not be +** called again on the same changegroup object until after +** sqlite3changegroup_change_finish() has been called. Doing so is an +** SQLITE_MISUSE error. +** +** The changegroup object passed as the first argument must be already +** configured with schema data for the specified table. It may be configured +** either by calling sqlite3changegroup_schema() with a database that contains +** the table, or sqlite3changegroup_add() with a changeset that contains the +** table. If the changegroup object has not been configured with a schema for +** the specified table when this function is called, SQLITE_ERROR is returned. +** +** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an +** SQLite error code is returned. In this case, if argument pzErr is non-NULL, +** then (*pzErr) may be set to point to a buffer containing a utf-8 formated, +** nul-terminated, English language error message. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup*, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +); + +/* +** CAPI3REF: Add a 64-bit integer to a changegroup +** +** This function may only be called between a successful call to +** sqlite3changegroup_change_begin() and its matching +** sqlite3changegroup_change_finish() call. If it is called at any +** other time, it is an SQLITE_MISUSE error. Calling this function +** specifies a 64-bit integer value to be used in the change currently being +** added to the changegroup object passed as the first argument. +** +** The second parameter, bNew, specifies whether the value is to be part of +** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of +** the change under construction. If this does not match the type of change +** specified by the preceding call to sqlite3changegroup_change_begin() (i.e. +** an old.* value for an SQLITE_INSERT change, or a new.* value for an +** SQLITE_DELETE), then SQLITE_ERROR is returned. +** +** The third parameter specifies the column of the old.* or new.* record that +** the value will be a part of. If the specified table has an explicit primary +** key, then this is the index of the table column, numbered from 0 in the order +** specified within the CREATE TABLE statement. Or, if the table uses an +** implicit rowid key, then the column 0 is the rowid and the explicit columns +** are numbered starting from 1. If the iCol parameter is less than 0 or greater +** than the index of the last column in the table, SQLITE_RANGE is returned. +** +** The fourth parameter is the integer value to use as part of the old.* or +** new.* record. +** +** If this call is successful, SQLITE_OK is returned. Otherwise, if an +** error occurs, an SQLite error code is returned. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup*, + int bNew, + int iCol, + sqlite3_int64 iVal +); + +/* +** CAPI3REF: Add a NULL to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently under construction with a NULL value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int); + +/* +** CAPI3REF: Add an double to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently being constructed with a real value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double); + +/* +** CAPI3REF: Add a text value to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a text value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the text encoded using +** utf-8. Parameter nVal may either be the size of the text value in bytes, or +** else a negative value, in which case the buffer pVal points to is assumed to +** be nul-terminated. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup*, int, int, const char *pVal, int nVal +); + +/* +** CAPI3REF: Add a blob to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a blob value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the blob. Parameter +** nVal is the size of the blob in bytes. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup*, int, int, const void *pVal, int nVal +); + +/* +** CAPI3REF: Finish adding one-at-at-time changes to a changegroup +** +** This function may only be called following a successful call to +** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error. +** +** If parameter bDiscard is non-zero, then the current change is simply +** discarded. In this case this function is always successful and SQLITE_OK +** returned. +** +** If parameter bDiscard is zero, then an attempt is made to add the current +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: +** +** * If the change is an INSERT or DELETE, then a value must be specified +** for all columns of the new.* or old.* record, respectively. +** +** * If the change is an UPDATE record, then values must be provided for +** the PRIMARY KEY columns of the old.* record, but must not be provided +** for PRIMARY KEY columns of the new.* record. +** +** * If the change is an UPDATE record, then for each non-PRIMARY KEY +** column in the old.* record for which a value has been provided, a +** value must also be provided for the same column in the new.* record. +** Similarly, for each non-PK column in the old.* record for which +** a value is not provided, a value must not be provided for the same +** column in the new.* record. +** +** * All values specified for PRIMARY KEY columns must be non-NULL. +** +** Otherwise, it is an error. +** +** If the changegroup already contains a change for the same row (identified +** by PRIMARY KEY columns), then the current change is combined with the +** existing change in the same way as for sqlite3changegroup_add(). +** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** +** If the call is successful, SQLITE_OK is returned. Otherwise, if an error +** occurs, an SQLite error code is returned. If an error is returned and +** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer +** containing a nul-terminated, utf-8 encoded, English language error message. +** It is the responsibility of the caller to eventually free any such error +** message buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup*, + int bDiscard, + char **pzErr +); + /* ** Make sure we can call this stuff from C++. */ @@ -14334,6 +14701,27 @@ struct fts5_api { #endif #define SQLITE_MIN_LENGTH 30 /* Minimum value for the length limit */ +/* +** Maximum size of any single memory allocation. +** +** This is not a limit on the total amount of memory used. This is +** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc(). +** +** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391 +** This provides a 256-byte safety margin for defense against 32-bit +** signed integer overflow bugs when computing memory allocation sizes. +** Paranoid applications might want to reduce the maximum allocation size +** further for an even larger safety margin. 0x3fffffff or 0x0fffffff +** or even smaller would be reasonable upper bounds on the size of a memory +** allocations for most applications. +*/ +#ifndef SQLITE_MAX_ALLOCATION_SIZE +# define SQLITE_MAX_ALLOCATION_SIZE 2147483391 +#endif +#if SQLITE_MAX_ALLOCATION_SIZE>2147483391 +# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391 +#endif + /* ** This is the maximum number of ** @@ -14369,21 +14757,42 @@ struct fts5_api { ** It used to be the case that setting this value to zero would ** turn the limit off. That is no longer true. It is not possible ** to turn this limit off. +** +** The hard limit is the largest possible 32-bit signed integer less +** 1024, or 2147482624. */ #ifndef SQLITE_MAX_SQL_LENGTH # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* -** The maximum depth of an expression tree. This is limited to -** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might -** want to place more severe limits on the complexity of an -** expression. A value of 0 means that there is no limit. +** The maximum depth of an expression tree. The expression tree depth +** is also limited indirectly by SQLITE_MAX_SQL_LENGTH and by +** SQLITE_MAX_PARSER_DEPTH. Reducing the maximum complexity of +** expressions can help prevent excess memory usage by hostile SQL. +** +** A value of 0 for this compile-time option causes all expression +** depth limiting code to be omitted. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif +/* +** The maximum depth of the LALR(1) stack used in the parser that +** interprets SQL inputs. The parser stack depth can also be limited +** indirectly by SQLITE_MAX_SQL_LENGTH. Limiting the parser stack +** depth can help prevent excess memory usage and excess CPU stack +** usage when processing hostile SQL. +** +** Prior to version 3.45.0 (2024-01-15), the parser stack was +** hard-coded to 100 entries, and that worked fine for almost all +** applications. So the upper bound on this limit need not be large. +*/ +#ifndef SQLITE_MAX_PARSER_DEPTH +# define SQLITE_MAX_PARSER_DEPTH 2500 +#endif + /* ** The maximum number of terms in a compound SELECT statement. ** The code generator for compound SELECT statements does one @@ -14499,6 +14908,10 @@ struct fts5_api { # undef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif +#if SQLITE_MAX_DEFAULT_PAGE_SIZE -#endif #ifdef HAVE_INTTYPES_H #include #endif @@ -15269,6 +15680,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define float sqlite_int64 # define fabs(X) ((X)<0?-(X):(X)) # define sqlite3IsOverflow(X) 0 +# define INFINITY (9223372036854775807LL) # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif @@ -15678,6 +16090,7 @@ typedef INT16_TYPE LogEst; #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif +#define TWO_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&1)==0) /* ** Disable MMAP on platforms where it is known to not work @@ -17136,6 +17549,7 @@ struct VdbeOp { SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ Table *pTab; /* Used when p4type is P4_TABLE */ SubrtnSig *pSubrtnSig; /* Used when p4type is P4_SUBRTNSIG */ + Index *pIdx; /* Used when p4type is P4_INDEX */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif @@ -17190,20 +17604,21 @@ typedef struct VdbeOpList VdbeOpList; #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ #define P4_TABLE (-5) /* P4 is a pointer to a Table structure */ +#define P4_INDEX (-6) /* P4 is a pointer to an Index structure */ /* Above do not own any resources. Must free those below */ -#define P4_FREE_IF_LE (-6) -#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */ -#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */ -#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */ -#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */ -#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */ -#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */ -#define P4_REAL (-12) /* P4 is a 64-bit floating point value */ -#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ -#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */ -#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */ -#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */ -#define P4_SUBRTNSIG (-17) /* P4 is a SubrtnSig pointer */ +#define P4_FREE_IF_LE (-7) +#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ +#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ +#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ +#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ +#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ +#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ +#define P4_REAL (-13) /* P4 is a 64-bit floating point value */ +#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ +#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ +#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ +#define P4_TABLEREF (-17) /* Like P4_TABLE, but reference counted */ +#define P4_SUBRTNSIG (-18) /* P4 is a SubrtnSig pointer */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 @@ -17292,10 +17707,10 @@ typedef struct VdbeOpList VdbeOpList; #define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */ #define OP_IdxLT 45 /* jump, synopsis: key=r[P3@P4] */ #define OP_IdxGE 46 /* jump, synopsis: key=r[P3@P4] */ -#define OP_RowSetRead 47 /* jump, synopsis: r[P3]=rowset(P1) */ -#define OP_RowSetTest 48 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ -#define OP_Program 49 /* jump0 */ -#define OP_FkIfZero 50 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IFindKey 47 /* jump */ +#define OP_RowSetRead 48 /* jump, synopsis: r[P3]=rowset(P1) */ +#define OP_RowSetTest 49 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */ +#define OP_Program 50 /* jump0 */ #define OP_IsNull 51 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */ #define OP_NotNull 52 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */ #define OP_Ne 53 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */ @@ -17305,49 +17720,49 @@ typedef struct VdbeOpList VdbeOpList; #define OP_Lt 57 /* jump, same as TK_LT, synopsis: IF r[P3]=r[P1] */ #define OP_ElseEq 59 /* jump, same as TK_ESCAPE */ -#define OP_IfPos 60 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ -#define OP_IfNotZero 61 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ -#define OP_DecrJumpZero 62 /* jump, synopsis: if (--r[P1])==0 goto P2 */ -#define OP_IncrVacuum 63 /* jump */ -#define OP_VNext 64 /* jump */ -#define OP_Filter 65 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ -#define OP_PureFunc 66 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Function 67 /* synopsis: r[P3]=func(r[P2@NP]) */ -#define OP_Return 68 -#define OP_EndCoroutine 69 -#define OP_HaltIfNull 70 /* synopsis: if r[P3]=null halt */ -#define OP_Halt 71 -#define OP_Integer 72 /* synopsis: r[P2]=P1 */ -#define OP_Int64 73 /* synopsis: r[P2]=P4 */ -#define OP_String 74 /* synopsis: r[P2]='P4' (len=P1) */ -#define OP_BeginSubrtn 75 /* synopsis: r[P2]=NULL */ -#define OP_Null 76 /* synopsis: r[P2..P3]=NULL */ -#define OP_SoftNull 77 /* synopsis: r[P1]=NULL */ -#define OP_Blob 78 /* synopsis: r[P2]=P4 (len=P1) */ -#define OP_Variable 79 /* synopsis: r[P2]=parameter(P1) */ -#define OP_Move 80 /* synopsis: r[P2@P3]=r[P1@P3] */ -#define OP_Copy 81 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ -#define OP_SCopy 82 /* synopsis: r[P2]=r[P1] */ -#define OP_IntCopy 83 /* synopsis: r[P2]=r[P1] */ -#define OP_FkCheck 84 -#define OP_ResultRow 85 /* synopsis: output=r[P1@P2] */ -#define OP_CollSeq 86 -#define OP_AddImm 87 /* synopsis: r[P1]=r[P1]+P2 */ -#define OP_RealAffinity 88 -#define OP_Cast 89 /* synopsis: affinity(r[P1]) */ -#define OP_Permutation 90 -#define OP_Compare 91 /* synopsis: r[P1@P3] <-> r[P2@P3] */ -#define OP_IsTrue 92 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ -#define OP_ZeroOrNull 93 /* synopsis: r[P2] = 0 OR NULL */ -#define OP_Offset 94 /* synopsis: r[P3] = sqlite_offset(P1) */ -#define OP_Column 95 /* synopsis: r[P3]=PX cursor P1 column P2 */ -#define OP_TypeCheck 96 /* synopsis: typecheck(r[P1@P2]) */ -#define OP_Affinity 97 /* synopsis: affinity(r[P1@P2]) */ -#define OP_MakeRecord 98 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ -#define OP_Count 99 /* synopsis: r[P2]=count() */ -#define OP_ReadCookie 100 -#define OP_SetCookie 101 -#define OP_ReopenIdx 102 /* synopsis: root=P2 iDb=P3 */ +#define OP_FkIfZero 60 /* jump, synopsis: if fkctr[P1]==0 goto P2 */ +#define OP_IfPos 61 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */ +#define OP_IfNotZero 62 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */ +#define OP_DecrJumpZero 63 /* jump, synopsis: if (--r[P1])==0 goto P2 */ +#define OP_IncrVacuum 64 /* jump */ +#define OP_VNext 65 /* jump */ +#define OP_Filter 66 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */ +#define OP_PureFunc 67 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Function 68 /* synopsis: r[P3]=func(r[P2@NP]) */ +#define OP_Return 69 +#define OP_EndCoroutine 70 +#define OP_HaltIfNull 71 /* synopsis: if r[P3]=null halt */ +#define OP_Halt 72 +#define OP_Integer 73 /* synopsis: r[P2]=P1 */ +#define OP_Int64 74 /* synopsis: r[P2]=P4 */ +#define OP_String 75 /* synopsis: r[P2]='P4' (len=P1) */ +#define OP_BeginSubrtn 76 /* synopsis: r[P2]=NULL */ +#define OP_Null 77 /* synopsis: r[P2..P3]=NULL */ +#define OP_SoftNull 78 /* synopsis: r[P1]=NULL */ +#define OP_Blob 79 /* synopsis: r[P2]=P4 (len=P1) */ +#define OP_Variable 80 /* synopsis: r[P2]=parameter(P1) */ +#define OP_Move 81 /* synopsis: r[P2@P3]=r[P1@P3] */ +#define OP_Copy 82 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */ +#define OP_SCopy 83 /* synopsis: r[P2]=r[P1] */ +#define OP_IntCopy 84 /* synopsis: r[P2]=r[P1] */ +#define OP_FkCheck 85 +#define OP_ResultRow 86 /* synopsis: output=r[P1@P2] */ +#define OP_CollSeq 87 +#define OP_AddImm 88 /* synopsis: r[P1]=r[P1]+P2 */ +#define OP_RealAffinity 89 +#define OP_Cast 90 /* synopsis: affinity(r[P1]) */ +#define OP_Permutation 91 +#define OP_Compare 92 /* synopsis: r[P1@P3] <-> r[P2@P3] */ +#define OP_IsTrue 93 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */ +#define OP_ZeroOrNull 94 /* synopsis: r[P2] = 0 OR NULL */ +#define OP_Offset 95 /* synopsis: r[P3] = sqlite_offset(P1) */ +#define OP_Column 96 /* synopsis: r[P3]=PX cursor P1 column P2 */ +#define OP_TypeCheck 97 /* synopsis: typecheck(r[P1@P2]) */ +#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */ +#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */ +#define OP_Count 100 /* synopsis: r[P2]=count() */ +#define OP_ReadCookie 101 +#define OP_SetCookie 102 #define OP_BitAnd 103 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */ #define OP_BitOr 104 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */ #define OP_ShiftLeft 105 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ -#define OP_AggInverse 162 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ -#define OP_AggStep 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggStep1 164 /* synopsis: accum=r[P3] step(r[P2@P5]) */ -#define OP_AggValue 165 /* synopsis: r[P3]=value N=P2 */ -#define OP_AggFinal 166 /* synopsis: accum=r[P1] N=P2 */ -#define OP_Expire 167 -#define OP_CursorLock 168 -#define OP_CursorUnlock 169 -#define OP_TableLock 170 /* synopsis: iDb=P1 root=P2 write=P3 */ -#define OP_VBegin 171 -#define OP_VCreate 172 -#define OP_VDestroy 173 -#define OP_VOpen 174 -#define OP_VCheck 175 -#define OP_VInitIn 176 /* synopsis: r[P2]=ValueList(P1,P3) */ -#define OP_VColumn 177 /* synopsis: r[P3]=vcolumn(P2) */ -#define OP_VRename 178 -#define OP_Pagecount 179 -#define OP_MaxPgcnt 180 -#define OP_ClrSubtype 181 /* synopsis: r[P1].subtype = 0 */ -#define OP_GetSubtype 182 /* synopsis: r[P2] = r[P1].subtype */ -#define OP_SetSubtype 183 /* synopsis: r[P2].subtype = r[P1] */ -#define OP_FilterAdd 184 /* synopsis: filter(P1) += key(P3@P4) */ -#define OP_Trace 185 -#define OP_CursorHint 186 -#define OP_ReleaseReg 187 /* synopsis: release r[P1@P2] mask P3 */ -#define OP_Noop 188 -#define OP_Explain 189 -#define OP_Abortable 190 +#define OP_DropIndex 155 +#define OP_DropTrigger 156 +#define OP_IntegrityCk 157 +#define OP_RowSetAdd 158 /* synopsis: rowset(P1)=r[P2] */ +#define OP_Param 159 +#define OP_FkCounter 160 /* synopsis: fkctr[P1]+=P2 */ +#define OP_MemMax 161 /* synopsis: r[P1]=max(r[P1],r[P2]) */ +#define OP_OffsetLimit 162 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */ +#define OP_AggInverse 163 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */ +#define OP_AggStep 164 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggStep1 165 /* synopsis: accum=r[P3] step(r[P2@P5]) */ +#define OP_AggValue 166 /* synopsis: r[P3]=value N=P2 */ +#define OP_AggFinal 167 /* synopsis: accum=r[P1] N=P2 */ +#define OP_Expire 168 +#define OP_CursorLock 169 +#define OP_CursorUnlock 170 +#define OP_TableLock 171 /* synopsis: iDb=P1 root=P2 write=P3 */ +#define OP_VBegin 172 +#define OP_VCreate 173 +#define OP_VDestroy 174 +#define OP_VOpen 175 +#define OP_VCheck 176 +#define OP_VInitIn 177 /* synopsis: r[P2]=ValueList(P1,P3) */ +#define OP_VColumn 178 /* synopsis: r[P3]=vcolumn(P2) */ +#define OP_VRename 179 +#define OP_Pagecount 180 +#define OP_MaxPgcnt 181 +#define OP_ClrSubtype 182 /* synopsis: r[P1].subtype = 0 */ +#define OP_GetSubtype 183 /* synopsis: r[P2] = r[P1].subtype */ +#define OP_SetSubtype 184 /* synopsis: r[P2].subtype = r[P1] */ +#define OP_FilterAdd 185 /* synopsis: filter(P1) += key(P3@P4) */ +#define OP_Trace 186 +#define OP_CursorHint 187 +#define OP_ReleaseReg 188 /* synopsis: release r[P1@P2] mask P3 */ +#define OP_Noop 189 +#define OP_Explain 190 +#define OP_Abortable 191 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c @@ -17455,25 +17871,26 @@ typedef struct VdbeOpList VdbeOpList; /* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0xc9, 0xc9, 0xc9,\ /* 24 */ 0xc9, 0x01, 0x49, 0x49, 0x49, 0x49, 0xc9, 0x49,\ /* 32 */ 0xc1, 0x01, 0x41, 0x41, 0xc1, 0x01, 0x01, 0x41,\ -/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x41, 0x23,\ -/* 48 */ 0x0b, 0x81, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ -/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01,\ -/* 64 */ 0x41, 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00,\ -/* 72 */ 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10,\ -/* 80 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02,\ -/* 88 */ 0x02, 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40,\ -/* 96 */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26,\ +/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x41, 0x09,\ +/* 48 */ 0x23, 0x0b, 0x81, 0x03, 0x03, 0x0b, 0x0b, 0x0b,\ +/* 56 */ 0x0b, 0x0b, 0x0b, 0x01, 0x01, 0x03, 0x03, 0x03,\ +/* 64 */ 0x01, 0x41, 0x01, 0x00, 0x00, 0x02, 0x02, 0x08,\ +/* 72 */ 0x00, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10,\ +/* 80 */ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,\ +/* 88 */ 0x02, 0x02, 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20,\ +/* 96 */ 0x40, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x26,\ /* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\ -/* 112 */ 0x26, 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40,\ -/* 120 */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10,\ -/* 128 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,\ -/* 136 */ 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50,\ -/* 144 */ 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\ -/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00,\ -/* 160 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ -/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10,\ -/* 176 */ 0x50, 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12,\ -/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,} +/* 112 */ 0x26, 0x40, 0x40, 0x12, 0x00, 0x40, 0x10, 0x40,\ +/* 120 */ 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40,\ +/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ +/* 136 */ 0x00, 0x50, 0x00, 0x40, 0x04, 0x04, 0x00, 0x40,\ +/* 144 */ 0x50, 0x40, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00,\ +/* 152 */ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x10,\ +/* 160 */ 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,\ +/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,\ +/* 176 */ 0x10, 0x50, 0x40, 0x00, 0x10, 0x10, 0x02, 0x12,\ +/* 184 */ 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ +} /* The resolve3P2Values() routine is able to run faster if it knows ** the value of the largest JUMP opcode. The smaller the maximum @@ -17481,7 +17898,7 @@ typedef struct VdbeOpList VdbeOpList; ** generated this include file strives to group all JUMP opcodes ** together near the beginning of the list. */ -#define SQLITE_MX_JUMP_OPCODE 65 /* Maximum JUMP opcode */ +#define SQLITE_MX_JUMP_OPCODE 66 /* Maximum JUMP opcode */ /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ @@ -17490,7 +17907,7 @@ typedef struct VdbeOpList VdbeOpList; ** Additional non-public SQLITE_PREPARE_* flags */ #define SQLITE_PREPARE_SAVESQL 0x80 /* Preserve SQL text */ -#define SQLITE_PREPARE_MASK 0x1f /* Mask of public flags */ +#define SQLITE_PREPARE_MASK 0x3f /* Mask of public flags */ /* ** Prototypes for the VDBE interface. See comments on the implementation @@ -17772,10 +18189,10 @@ struct PgHdr { PCache *pCache; /* PRIVATE: Cache that owns this page */ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */ Pager *pPager; /* The pager this page is part of */ - Pgno pgno; /* Page number for this page */ #ifdef SQLITE_CHECK_PAGES - u32 pageHash; /* Hash of page content */ + u64 pageHash; /* Hash of page content */ #endif + Pgno pgno; /* Page number for this page */ u16 flags; /* PGHDR flags defined below */ /********************************************************************** @@ -18115,7 +18532,7 @@ struct Schema { ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ -#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1) +#define SQLITE_N_LIMIT (SQLITE_LIMIT_PARSER_DEPTH+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used @@ -18269,6 +18686,7 @@ struct sqlite3 { u8 noSharedCache; /* True if no shared-cache backends */ u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */ u8 eOpenState; /* Current condition of the connection */ + u8 nFpDigit; /* Significant digits to keep on double->text */ int nextPagesize; /* Pagesize after VACUUM if >0 */ i64 nChange; /* Value returned by sqlite3_changes() */ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */ @@ -20163,19 +20581,6 @@ struct Upsert { /* ** An instance of the following structure contains all information ** needed to generate code for a single SELECT statement. -** -** See the header comment on the computeLimitRegisters() routine for a -** detailed description of the meaning of the iLimit and iOffset fields. -** -** addrOpenEphm[] entries contain the address of OP_OpenEphemeral opcodes. -** These addresses must be stored so that we can go back and fill in -** the P4_KEYINFO and P2 parameters later. Neither the KeyInfo nor -** the number of columns in P2 can be computed at the same time -** as the OP_OpenEphm instruction is coded because not -** enough information about the compound query is known at that point. -** The KeyInfo for addrOpenTran[0] and [1] contains collating sequences -** for the result set. The KeyInfo for addrOpenEphm[2] contains collating -** sequences for the ORDER BY clause. */ struct Select { u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ @@ -20183,7 +20588,6 @@ struct Select { u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ u32 selId; /* Unique identifier number for this SELECT */ - int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ ExprList *pEList; /* The fields of the result */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ @@ -20215,7 +20619,7 @@ struct Select { #define SF_Resolved 0x0000004 /* Identifiers have been resolved */ #define SF_Aggregate 0x0000008 /* Contains agg functions or a GROUP BY */ #define SF_HasAgg 0x0000010 /* Contains aggregate functions */ -#define SF_UsesEphemeral 0x0000020 /* Uses the OpenEphemeral opcode */ +#define SF_ClonedRhsIn 0x0000020 /* Cloned RHS of an IN operator */ #define SF_Expanded 0x0000040 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0000080 /* FROM subqueries have Table metadata */ #define SF_Compound 0x0000100 /* Part of a compound query */ @@ -20225,14 +20629,14 @@ struct Select { #define SF_MinMaxAgg 0x0001000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x0002000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x0004000 /* nSelectRow set by a constant LIMIT */ -#define SF_MaybeConvert 0x0008000 /* Need convertCompoundSelectToSubquery() */ +/* 0x0008000 // available for reuse */ #define SF_Converted 0x0010000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x0020000 /* Include hidden columns in output */ #define SF_ComplexResult 0x0040000 /* Result contains subquery or function */ #define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */ #define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */ #define SF_View 0x0200000 /* SELECT statement is a view */ -#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ +/* 0x0400000 // available for reuse */ #define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */ #define SF_PushDown 0x1000000 /* Modified by WHERE-clause push-down opt */ #define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */ @@ -20252,11 +20656,6 @@ struct Select { ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** -** SRT_Union Store results as a key in a temporary index -** identified by pDest->iSDParm. -** -** SRT_Except Remove results from the temporary index pDest->iSDParm. -** ** SRT_Exists Store a 1 in memory cell pDest->iSDParm if the result ** set is not empty. ** @@ -20320,30 +20719,28 @@ struct Select { ** table. (pDest->iSDParm) is the number of key columns in ** each index record in this case. */ -#define SRT_Union 1 /* Store result as keys in an index */ -#define SRT_Except 2 /* Remove result from a UNION index */ -#define SRT_Exists 3 /* Store 1 if the result is not empty */ -#define SRT_Discard 4 /* Do not save the results anywhere */ -#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */ -#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */ +#define SRT_Exists 1 /* Store 1 if the result is not empty */ +#define SRT_Discard 2 /* Do not save the results anywhere */ +#define SRT_DistFifo 3 /* Like SRT_Fifo, but unique results only */ +#define SRT_DistQueue 4 /* Like SRT_Queue, but unique results only */ /* The DISTINCT clause is ignored for all of the above. Not that ** IgnorableDistinct() implies IgnorableOrderby() */ #define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue) -#define SRT_Queue 7 /* Store result in an queue */ -#define SRT_Fifo 8 /* Store result as data with an automatic rowid */ +#define SRT_Queue 5 /* Store result in an queue */ +#define SRT_Fifo 6 /* Store result as data with an automatic rowid */ /* The ORDER BY clause is ignored for all of the above */ #define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo) -#define SRT_Output 9 /* Output each row of result */ -#define SRT_Mem 10 /* Store result in a memory cell */ -#define SRT_Set 11 /* Store results as keys in an index */ -#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */ -#define SRT_Coroutine 13 /* Generate a single row of result */ -#define SRT_Table 14 /* Store result as data with an automatic rowid */ -#define SRT_Upfrom 15 /* Store result as data with rowid */ +#define SRT_Output 7 /* Output each row of result */ +#define SRT_Mem 8 /* Store result in a memory cell */ +#define SRT_Set 9 /* Store results as keys in an index */ +#define SRT_EphemTab 10 /* Create transient tab and store like SRT_Table */ +#define SRT_Coroutine 11 /* Generate a single row of result */ +#define SRT_Table 12 /* Store result as data with an automatic rowid */ +#define SRT_Upfrom 13 /* Store result as data with rowid */ /* ** An instance of this object describes where to put of the results of @@ -20479,17 +20876,12 @@ struct Parse { u8 nested; /* Number of nested calls to the parser/code generator */ u8 nTempReg; /* Number of temporary registers in aTempReg[] */ u8 isMultiWrite; /* True if statement may modify/insert multiple rows */ - u8 mayAbort; /* True if statement may throw an ABORT exception */ - u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */ u8 disableLookaside; /* Number of times lookaside has been disabled */ u8 prepFlags; /* SQLITE_PREPARE_* flags */ u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */ - u8 bHasExists; /* Has a correlated "EXISTS (SELECT ....)" expression */ u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */ - u8 bReturning; /* Coding a RETURNING trigger */ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */ - u8 disableTriggers; /* True to disable triggers */ #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST) u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */ #endif @@ -20498,10 +20890,15 @@ struct Parse { u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER) ** and ALTER TABLE ADD COLUMN. */ #endif - bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ - bft bHasWith :1; /* True if statement contains WITH */ - bft okConstFactor :1; /* OK to factor out constants */ - bft checkSchema :1; /* Causes schema cookie check after an error */ + bft disableTriggers:1; /* True to disable triggers */ + bft mayAbort :1; /* True if statement may throw an ABORT exception */ + bft hasCompound :1; /* Need to invoke convertCompoundSelectToSubquery() */ + bft bReturning :1; /* Coding a RETURNING trigger */ + bft bHasExists :1; /* Has a correlated "EXISTS (SELECT ....)" expression */ + bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */ + bft bHasWith :1; /* True if statement contains WITH */ + bft okConstFactor:1; /* OK to factor out constants */ + bft checkSchema :1; /* Causes schema cookie check after an error */ int nRangeReg; /* Size of the temporary register block */ int iRangeReg; /* First register in temporary register block */ int nErr; /* Number of errors seen */ @@ -20730,19 +21127,19 @@ struct Trigger { ** orconf -> stores the ON CONFLICT algorithm ** pSelect -> The content to be inserted - either a SELECT statement or ** a VALUES clause. -** zTarget -> Dequoted name of the table to insert into. +** pSrc -> Table to insert into. ** pIdList -> If this is an INSERT INTO ... () VALUES ... ** statement, then this stores the column-names to be ** inserted into. ** pUpsert -> The ON CONFLICT clauses for an Upsert ** ** (op == TK_DELETE) -** zTarget -> Dequoted name of the table to delete from. +** pSrc -> Table to delete from ** pWhere -> The WHERE clause of the DELETE statement if one is specified. ** Otherwise NULL. ** ** (op == TK_UPDATE) -** zTarget -> Dequoted name of the table to update. +** pSrc -> Table to update, followed by any FROM clause tables. ** pWhere -> The WHERE clause of the UPDATE statement if one is specified. ** Otherwise NULL. ** pExprList -> A list of the columns to update and the expressions to update @@ -20762,8 +21159,7 @@ struct TriggerStep { u8 orconf; /* OE_Rollback etc. */ Trigger *pTrig; /* The trigger that this step is a part of */ Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */ - char *zTarget; /* Target table for DELETE, UPDATE, INSERT */ - SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */ + SrcList *pSrc; /* Table to insert/update/delete */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */ IdList *pIdList; /* Column names for INSERT */ @@ -20846,10 +21242,11 @@ typedef struct { /* ** Allowed values for mInitFlags */ -#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */ +#define INITFLAG_AlterMask 0x0007 /* Types of ALTER */ #define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */ #define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */ #define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */ +#define INITFLAG_AlterDropCons 0x0004 /* Reparse after an ADD COLUMN */ /* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled ** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning @@ -20979,6 +21376,7 @@ struct Walker { NameContext *pNC; /* Naming context */ int n; /* A counter */ int iCur; /* A cursor number */ + int sz; /* String literal length */ SrcList *pSrcList; /* FROM clause */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */ @@ -21383,7 +21781,20 @@ SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3*,int*); SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void); SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void); -#if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) + +/* The SQLITE_THREAD_MISUSE_WARNINGS compile-time option used to be called +** SQLITE_ENABLE_MULTITHREADED_CHECKS. Keep that older macro for backwards +** compatibility, at least for a while... */ +#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +/* SQLITE_THREAD_MISUSE_ABORT implies SQLITE_THREAD_MISUSE_WARNINGS */ +#ifdef SQLITE_THREAD_MISUSE_ABORT +# define SQLITE_THREAD_MISUSE_WARNINGS 1 +#endif + +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) && !defined(SQLITE_MUTEX_OMIT) SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) @@ -21412,17 +21823,22 @@ struct PrintfArguments { sqlite3_value **apArg; /* The argument values */ }; +/* +** Maxium number of base-10 digits in an unsigned 64-bit integer +*/ +#define SQLITE_U64_DIGITS 20 + /* ** An instance of this object receives the decoding of a floating point ** value into an approximate decimal representation. */ struct FpDecode { - char sign; /* '+' or '-' */ - char isSpecial; /* 1: Infinity 2: NaN */ - int n; /* Significant digits in the decode */ - int iDP; /* Location of the decimal point */ - char *z; /* Start of significant digits */ - char zBuf[24]; /* Storage for significant digits */ + int n; /* Significant digits in the decode */ + int iDP; /* Location of the decimal point */ + char *z; /* Start of significant digits */ + char zBuf[SQLITE_U64_DIGITS+1]; /* Storage for significant digits */ + char sign; /* '+' or '-' */ + char isSpecial; /* 1: Infinity 2: NaN */ }; SQLITE_PRIVATE void sqlite3FpDecode(FpDecode*,double,int,int); @@ -21511,6 +21927,7 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int); #endif SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int); SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*); +SQLITE_PRIVATE Expr *sqlite3ExprInt32(sqlite3*,int); SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*); SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*); @@ -21664,6 +22081,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList Expr*,ExprList*,u32,Expr*); SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*); SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*); +SQLITE_PRIVATE void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect); SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*); SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*); SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); @@ -21761,6 +22179,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*); SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*, Parse*); SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*); SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); +SQLITE_PRIVATE int sqlite3ExprIsLikeOperator(const Expr*); SQLITE_PRIVATE int sqlite3IsRowid(const char*); SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab); SQLITE_PRIVATE void sqlite3GenerateRowDelete( @@ -21829,17 +22248,16 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, i SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,SrcList*, IdList*, Select*,u8,Upsert*, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,SrcList*,SrcList*,ExprList*, Expr*, u8, const char*,const char*); -SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*, +SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,SrcList*, Expr*, const char*,const char*); SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*); SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int); -SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else @@ -21853,7 +22271,6 @@ SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*); # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 -# define sqlite3TriggerStepSrc(A,B) 0 #endif SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*); @@ -21886,7 +22303,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64); SQLITE_PRIVATE i64 sqlite3RealToI64(double); SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*); -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*); SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*); SQLITE_PRIVATE int sqlite3Atoi(const char*); @@ -22030,10 +22447,13 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*); SQLITE_PRIVATE void sqlite3AlterFunctions(void); SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); SQLITE_PRIVATE void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); +SQLITE_PRIVATE void sqlite3AlterDropConstraint(Parse*,SrcList*,Token*,Token*); +SQLITE_PRIVATE void sqlite3AlterAddConstraint(Parse*,SrcList*,Token*,Token*,const char*,int); +SQLITE_PRIVATE void sqlite3AlterSetNotNull(Parse*, SrcList*, Token*, Token*); SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *, int *); SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...); SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int); -SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int); +SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int); SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*); SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*); SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*); @@ -22106,6 +22526,7 @@ SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64); SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int); SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64); +SQLITE_PRIVATE int sqlite3StrAccumEnlargeIfNeeded(StrAccum*, i64); SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*); SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8); SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*); @@ -23333,6 +23754,9 @@ static const char * const sqlite3azCompileOpt[] = { #ifdef SQLITE_STMTJRNL_SPILL "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL), #endif +#ifdef SQLITE_STRICT_SUBTYPE + "STRICT_SUBTYPE", +#endif #ifdef SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif @@ -24448,6 +24872,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*); SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*)); +SQLITE_PRIVATE int sqlite3VdbeMemSetText(Mem*, const char*, i64, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64); #ifdef SQLITE_OMIT_FLOATING_POINT # define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64 @@ -24466,13 +24891,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int); SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*); #endif SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*); -SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*); +SQLITE_PRIVATE int sqlite3VdbeMemZeroTerminateIfAble(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8); SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double); SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*); SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*); SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*); +SQLITE_PRIVATE int sqlite3MemRealValueRC(Mem*, double*); SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull); SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*); SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*); @@ -24503,6 +24929,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook( Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int); #endif SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p); +SQLITE_PRIVATE int sqlite3VdbeFindIndexKey(BtCursor*, Index*, UnpackedRecord*, int*, int); SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); SQLITE_PRIVATE void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); @@ -25432,7 +25859,7 @@ static int parseDateOrTime( return 0; }else if( sqlite3StrICmp(zDate,"now")==0 && sqlite3NotPureFunc(context) ){ return setDateTimeToCurrent(context, p); - }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){ + }else if( sqlite3AtoF(zDate, &r)>0 ){ setRawDateNumber(p, r); return 0; }else if( (sqlite3StrICmp(zDate,"subsec")==0 @@ -25878,7 +26305,7 @@ static int parseModifier( ** date is already on the appropriate weekday, this is a no-op. */ if( sqlite3_strnicmp(z, "weekday ", 8)==0 - && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0 + && sqlite3AtoF(&z[8], &r)>0 && r>=0.0 && r<7.0 && (n=(int)r)==r ){ sqlite3_int64 Z; computeYMD_HMS(p); @@ -25949,9 +26376,11 @@ static int parseModifier( case '8': case '9': { double rRounder; - int i; + int i, rx; int Y,M,D,h,m,x; const char *z2 = z; + char *zCopy; + sqlite3 *db = sqlite3_context_db_handle(pCtx); char z0 = z[0]; for(n=1; z[n]; n++){ if( z[n]==':' ) break; @@ -25961,7 +26390,11 @@ static int parseModifier( if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break; } } - if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){ + zCopy = sqlite3DbStrNDup(db, z, n); + if( zCopy==0 ) break; + rx = sqlite3AtoF(zCopy, &r)<=0; + sqlite3DbFree(db, zCopy); + if( rx ){ assert( rc==1 ); break; } @@ -26781,7 +27214,7 @@ static void datedebugFunc( char *zJson; zJson = sqlite3_mprintf( "{iJD:%lld,Y:%d,M:%d,D:%d,h:%d,m:%d,tz:%d," - "s:%.3f,validJD:%d,validYMS:%d,validHMS:%d," + "s:%.3f,validJD:%d,validYMD:%d,validHMS:%d," "nFloor:%d,rawS:%d,isError:%d,useSubsec:%d," "isUtc:%d,isLocal:%d}", x.iJD, x.Y, x.M, x.D, x.h, x.m, x.tz, @@ -29560,23 +29993,28 @@ static SQLITE_WSD int mutexIsInit = 0; #ifndef SQLITE_MUTEX_OMIT -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS /* -** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains +** This block (enclosed by SQLITE_THREAD_MISUSE_WARNINGS) contains ** the implementation of a wrapper around the system default mutex ** implementation (sqlite3DefaultMutex()). ** ** Most calls are passed directly through to the underlying default ** mutex implementation. Except, if a mutex is configured by calling ** sqlite3MutexWarnOnContention() on it, then if contention is ever -** encountered within xMutexEnter() a warning is emitted via sqlite3_log(). +** encountered within xMutexEnter() then a warning is emitted via +** sqlite3_log(). Furthermore, if SQLITE_THREAD_MISUSE_ABORT is +** defined then abort() is called after the sqlite3_log() warning. ** -** This type of mutex is used as the database handle mutex when testing -** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. +** This type of mutex is used on the database handle mutex when testing +** apps that usually use SQLITE_CONFIG_MULTITHREAD mode. A failure +** indicates that the app ought to be using SQLITE_OPEN_FULLMUTEX or +** similar because it is trying to use the same database handle from +** two different connections at the same time. */ /* -** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS +** Type for all mutexes used when SQLITE_THREAD_MISUSE_WARNINGS ** is defined. Variable CheckMutex.mutex is a pointer to the real mutex ** allocated by the system mutex implementation. Variable iType is usually set ** to the type of mutex requested - SQLITE_MUTEX_RECURSIVE, SQLITE_MUTEX_FAST @@ -29612,11 +30050,12 @@ static int checkMutexNotheld(sqlite3_mutex *p){ */ static int checkMutexInit(void){ pGlobalMutexMethods = sqlite3DefaultMutex(); - return SQLITE_OK; + return pGlobalMutexMethods->xMutexInit(); } static int checkMutexEnd(void){ + int rc = pGlobalMutexMethods->xMutexEnd(); pGlobalMutexMethods = 0; - return SQLITE_OK; + return rc; } /* @@ -29693,6 +30132,9 @@ static void checkMutexEnter(sqlite3_mutex *p){ sqlite3_log(SQLITE_MISUSE, "illegal multi-threaded access to database connection" ); +#if SQLITE_THREAD_MISUSE_ABORT + abort(); +#endif } pGlobalMutexMethods->xMutexEnter(pCheck->mutex); } @@ -29744,7 +30186,7 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){ pCheck->iType = SQLITE_MUTEX_WARNONCONTENTION; } } -#endif /* ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS */ +#endif /* ifdef SQLITE_THREAD_MISUSE_WARNINGS */ /* ** Initialize the mutex system. @@ -29761,7 +30203,7 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){ sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; if( sqlite3GlobalConfig.bCoreMutex ){ -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#ifdef SQLITE_THREAD_MISUSE_WARNINGS pFrom = multiThreadedCheckMutex(); #else pFrom = sqlite3DefaultMutex(); @@ -30609,14 +31051,6 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ # define SQLITE_OS_WINCE 0 #endif -/* -** Determine if we are dealing with WinRT, which provides only a subset of -** the full Win32 API. -*/ -#if !defined(SQLITE_OS_WINRT) -# define SQLITE_OS_WINRT 0 -#endif - /* ** For WinCE, some API function parameters do not appear to be declared as ** volatile. @@ -30631,7 +31065,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ ** For some Windows sub-platforms, the _beginthreadex() / _endthreadex() ** functions are not available (e.g. those not using MSVC, Cygwin, etc). */ -#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ +#if SQLITE_OS_WIN && !SQLITE_OS_WINCE && \ SQLITE_THREADSAFE>0 && !defined(__CYGWIN__) # define SQLITE_OS_WIN_THREADS 1 #else @@ -30748,11 +31182,7 @@ static int winMutexInit(void){ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; for(i=0; itrace = 1; #endif #endif -#if SQLITE_OS_WINRT - InitializeCriticalSectionEx(&p->mutex, 0, 0); -#else InitializeCriticalSection(&p->mutex); -#endif } break; } @@ -31310,27 +31736,6 @@ static void mallocWithAlarm(int n, void **pp){ *pp = p; } -/* -** Maximum size of any single memory allocation. -** -** This is not a limit on the total amount of memory used. This is -** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc(). -** -** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391 -** This provides a 256-byte safety margin for defense against 32-bit -** signed integer overflow bugs when computing memory allocation sizes. -** Paranoid applications might want to reduce the maximum allocation size -** further for an even larger safety margin. 0x3fffffff or 0x0fffffff -** or even smaller would be reasonable upper bounds on the size of a memory -** allocations for most applications. -*/ -#ifndef SQLITE_MAX_ALLOCATION_SIZE -# define SQLITE_MAX_ALLOCATION_SIZE 2147483391 -#endif -#if SQLITE_MAX_ALLOCATION_SIZE>2147483391 -# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391 -#endif - /* ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. @@ -31554,8 +31959,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){ sqlite3_free(pOld); /* IMP: R-26507-47431 */ return 0; } - if( nBytes>=0x7fffff00 ){ - /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ + if( nBytes>SQLITE_MAX_ALLOCATION_SIZE ){ return 0; } nOld = sqlite3MallocSize(pOld); @@ -32440,9 +32844,11 @@ SQLITE_API void sqlite3_str_vappendf( }while( longvalue>0 ); } length = (int)(&zOut[nOut-1]-bufpt); - while( precision>length ){ - *(--bufpt) = '0'; /* Zero pad */ - length++; + if( precision>length ){ /* zero pad */ + int nn = precision-length; + bufpt -= nn; + memset(bufpt,'0',nn); + length = precision; } if( cThousand ){ int nn = (length - 1)/3; /* Number of "," to insert */ @@ -32473,6 +32879,7 @@ SQLITE_API void sqlite3_str_vappendf( FpDecode s; int iRound; int j; + i64 szBufNeeded; /* Size needed to hold the output */ if( bArgList ){ realvalue = getDoubleArg(pArgList); @@ -32493,7 +32900,7 @@ SQLITE_API void sqlite3_str_vappendf( }else{ iRound = precision+1; } - sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16); + sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 20 : 16); if( s.isSpecial ){ if( s.isSpecial==2 ){ bufpt = flag_zeropad ? "null" : "NaN"; @@ -32561,17 +32968,15 @@ SQLITE_API void sqlite3_str_vappendf( }else{ e2 = s.iDP - 1; } - bufpt = buf; - { - i64 szBufNeeded; /* Size of a temporary buffer needed */ - szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; - if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3; - if( szBufNeeded > etBUFSIZE ){ - bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); - if( bufpt==0 ) return; - } + + szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+10; + if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3; + if( sqlite3StrAccumEnlargeIfNeeded(pAccum, szBufNeeded) ){ + width = length = 0; + break; } - zOut = bufpt; + bufpt = zOut = pAccum->zText + pAccum->nChar; + flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ @@ -32579,12 +32984,24 @@ SQLITE_API void sqlite3_str_vappendf( } /* Digits prior to the decimal point */ j = 0; + assert( s.n>0 ); if( e2<0 ){ *(bufpt++) = '0'; - }else{ + }else if( cThousand ){ for(; e2>=0; e2--){ *(bufpt++) = j1 ) *(bufpt++) = ','; + if( (e2%3)==0 && e2>1 ) *(bufpt++) = ','; + } + }else{ + j = e2+1; + if( j>s.n ) j = s.n; + memcpy(bufpt, s.z, j); + bufpt += j; + e2 -= j; + if( e2>=0 ){ + memset(bufpt, '0', e2+1); + bufpt += e2+1; + e2 = -1; } } /* The decimal point */ @@ -32593,12 +33010,26 @@ SQLITE_API void sqlite3_str_vappendf( } /* "0" digits after the decimal point but before the first ** significant digit of the number */ - for(e2++; e2<0 && precision>0; precision--, e2++){ - *(bufpt++) = '0'; + if( e2<(-1) && precision>0 ){ + int nn = -1-e2; + if( nn>precision ) nn = precision; + memset(bufpt, '0', nn); + bufpt += nn; + precision -= nn; } /* Significant digits after the decimal point */ - while( (precision--)>0 ){ - *(bufpt++) = j0 ){ + int nn = s.n - j; + if( NEVER(nn>precision) ) nn = precision; + if( nn>0 ){ + memcpy(bufpt, s.z+j, nn); + bufpt += nn; + precision -= nn; + } + if( precision>0 && !flag_rtz ){ + memset(bufpt, '0', precision); + bufpt += precision; + } } /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ @@ -32628,27 +33059,31 @@ SQLITE_API void sqlite3_str_vappendf( *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ } - *bufpt = 0; - /* The converted number is in buf[] and zero terminated. Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions. */ length = (int)(bufpt-zOut); - bufpt = zOut; - - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if( flag_zeropad && !flag_leftjustify && length < width){ - int i; - int nPad = width - length; - for(i=width; i>=nPad; i--){ - bufpt[i] = bufpt[i-nPad]; + assert( length <= szBufNeeded ); + if( lengthnChar += length; + zOut[length] = 0; + + /* Floating point conversions render directly into the output + ** buffer. Hence, don't just break out of the switch(). Bypass the + ** output buffer writing that occurs after the switch() by continuing + ** to the next character in the format string. */ + continue; } case etSIZE: if( !bArgList ){ @@ -32692,11 +33127,10 @@ SQLITE_API void sqlite3_str_vappendf( i64 nCopyBytes; if( nPrior > precision-1 ) nPrior = precision - 1; nCopyBytes = length*nPrior; - if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){ - sqlite3StrAccumEnlarge(pAccum, nCopyBytes); + if( sqlite3StrAccumEnlargeIfNeeded(pAccum, nCopyBytes) ){ + break; } - if( pAccum->accError ) break; - sqlite3_str_append(pAccum, + sqlite3_str_append(pAccum, &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes); precision -= nPrior; nPrior *= 2; @@ -33042,6 +33476,13 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){ return (int)N; } +SQLITE_PRIVATE int sqlite3StrAccumEnlargeIfNeeded(StrAccum *p, i64 N){ + if( N + p->nChar >= p->nAlloc ){ + sqlite3StrAccumEnlarge(p, N); + } + return p->accError; +} + /* ** Append N copies of character c to the given string buffer. */ @@ -33172,6 +33613,14 @@ SQLITE_API int sqlite3_str_length(sqlite3_str *p){ return p ? p->nChar : 0; } +/* Truncate the text of the string to be no more than N bytes. */ +SQLITE_API void sqlite3_str_truncate(sqlite3_str *p, int N){ + if( p!=0 && N>=0 && (u32)NnChar ){ + p->nChar = N; + p->zText[p->nChar] = 0; + } +} + /* Return the current value for p */ SQLITE_API char *sqlite3_str_value(sqlite3_str *p){ if( p==0 || p->nChar==0 ) return 0; @@ -33192,6 +33641,17 @@ SQLITE_API void sqlite3_str_reset(StrAccum *p){ p->zText = 0; } +/* +** Destroy a dynamically allocate sqlite3_str object and all +** of its content, all in one call. +*/ +SQLITE_API void sqlite3_str_free(sqlite3_str *p){ + if( p ){ + sqlite3_str_reset(p); + sqlite3_free(p); + } +} + /* ** Initialize a string accumulator. ** @@ -34805,7 +35265,13 @@ SQLITE_PRIVATE void sqlite3TreeViewTrigger( SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); } SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);} SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); } -SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); } +SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ + TreeView *pView = 0; + sqlite3TreeViewPush(&pView, 0); + sqlite3TreeViewLine(pView, "SRCLIST"); + sqlite3TreeViewSrcList(pView,p); + sqlite3TreeViewPop(&pView); +} SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); } SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); } SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); } @@ -35186,6 +35652,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ rc = sqlite3Win32Wait((HANDLE)p->tid); assert( rc!=WAIT_IO_COMPLETION ); bRc = CloseHandle((HANDLE)p->tid); + (void)bRc; /* Prevent warning when assert() is a no-op */ assert( bRc ); } if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; @@ -36325,266 +36792,613 @@ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){ return h; } -/* Double-Double multiplication. (x[0],x[1]) *= (y,yy) -** -** Reference: -** T. J. Dekker, "A Floating-Point Technique for Extending the -** Available Precision". 1971-07-26. +/* +** Two inputs are multiplied to get a 128-bit result. Write the +** lower 64-bits of the result into *pLo, and return the high-order +** 64 bits. */ -static void dekkerMul2(volatile double *x, double y, double yy){ - /* - ** The "volatile" keywords on parameter x[] and on local variables - ** below are needed force intermediate results to be truncated to - ** binary64 rather than be carried around in an extended-precision - ** format. The truncation is necessary for the Dekker algorithm to - ** work. Intel x86 floating point might omit the truncation without - ** the use of volatile. - */ - volatile double tx, ty, p, q, c, cc; - double hx, hy; - u64 m; - memcpy(&m, (void*)&x[0], 8); - m &= 0xfffffffffc000000LL; - memcpy(&hx, &m, 8); - tx = x[0] - hx; - memcpy(&m, &y, 8); - m &= 0xfffffffffc000000LL; - memcpy(&hy, &m, 8); - ty = y - hy; - p = hx*hy; - q = hx*ty + tx*hy; - c = p+q; - cc = p - c + q + tx*ty; - cc = x[0]*yy + x[1]*y + cc; - x[0] = c + cc; - x[1] = c - x[0]; - x[1] += cc; +static u64 sqlite3Multiply128(u64 a, u64 b, u64 *pLo){ +#if (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \ + && !defined(SQLITE_DISABLE_INTRINSIC) + __uint128_t r = (__uint128_t)a * b; + *pLo = (u64)r; + return (u64)(r>>64); +#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC) + *pLo = a*b; + return __umulh(a, b); +#else + u64 a0 = (u32)a; + u64 a1 = a >> 32; + u64 b0 = (u32)b; + u64 b1 = b >> 32; + u64 a0b0 = a0 * b0; + u64 a1b1 = a1 * b1; + u64 a0b1 = a0 * b1; + u64 a1b0 = a1 * b0; + u64 t = (a0b0 >> 32) + (u32)a0b1 + (u32)a1b0; + *pLo = (a0b0 & UINT64_C(0xffffffff)) | (t << 32); + return a1b1 + (a0b1>>32) + (a1b0>>32) + (t>>32); +#endif +} + +/* +** A is an unsigned 96-bit integer formed by (a<<32)+aLo. +** B is an unsigned 64-bit integer. +** +** Compute the upper 96 bits of 160-bit result of A*B. +** +** Write ((A*B)>>64 & 0xffffffff) (the middle 32 bits of A*B) +** into *pLo. Return the upper 64 bits of A*B. +** +** The lower 64 bits of A*B are discarded. +*/ +static u64 sqlite3Multiply160(u64 a, u32 aLo, u64 b, u32 *pLo){ +#if (defined(__GNUC__) || defined(__clang__)) \ + && (defined(__x86_64__) || defined(__aarch64__) || defined(__riscv)) \ + && !defined(SQLITE_DISABLE_INTRINSIC) + __uint128_t r = (__uint128_t)a * b; + r += ((__uint128_t)aLo * b) >> 32; + *pLo = (r>>32)&0xffffffff; + return r>>64; +#elif defined(_WIN64) && !defined(SQLITE_DISABLE_INTRINSIC) + u64 r1_hi = __umulh(a,b); + u64 r1_lo = a*b; + u64 r2 = (__umulh((u64)aLo,b)<<32) + ((aLo*b)>>32); + u64 t = r1_lo + r2; + if( t>32; + return r1_hi; +#else + u64 x2 = a>>32; + u64 x1 = a&0xffffffff; + u64 x0 = aLo; + u64 y1 = b>>32; + u64 y0 = b&0xffffffff; + u64 x2y1 = x2*y1; + u64 r4 = x2y1>>32; + u64 x2y0 = x2*y0; + u64 x1y1 = x1*y1; + u64 r3 = (x2y1 & 0xffffffff) + (x2y0 >>32) + (x1y1 >>32); + u64 x1y0 = x1*y0; + u64 x0y1 = x0*y1; + u64 r2 = (x2y0 & 0xffffffff) + (x1y1 & 0xffffffff) + + (x1y0 >>32) + (x0y1>>32); + u64 x0y0 = x0*y0; + u64 r1 = (x1y0 & 0xffffffff) + (x0y1 & 0xffffffff) + + (x0y0 >>32); + r2 += r1>>32; + r3 += r2>>32; + *pLo = r2&0xffffffff; + return (r4<<32) + r3; +#endif +} + +/* +** Return a u64 with the N-th bit set. +*/ +#define U64_BIT(N) (((u64)1)<<(N)) + +/* +** Range of powers of 10 that we need to deal with when converting +** IEEE754 doubles to and from decimal. +*/ +#define POWERSOF10_FIRST (-348) +#define POWERSOF10_LAST (+347) + +/* +** For any p between -348 and +347, return the integer part of +** +** pow(10,p) * pow(2,63-pow10to2(p)) +** +** Or, in other words, for any p in range, return the most significant +** 64 bits of pow(10,p). The pow(10,p) value is shifted left or right, +** as appropriate so the most significant 64 bits fit exactly into a +** 64-bit unsigned integer. +** +** Write into *pLo the next 32 significant bits of the answer after +** the first 64. +** +** Algorithm: +** +** (1) For p between 0 and 26, return the value directly from the aBase[] +** lookup table. +** +** (2) For p outside the range 0 to 26, use aScale[] for the initial value +** then refine that result (if necessary) by a single multiplication +** against aBase[]. +** +** The constant tables aBase[], aScale[], and aScaleLo[] are generated +** by the C program at ../tool/mkfptab.c run with the --round option. +*/ +static u64 powerOfTen(int p, u32 *pLo){ + static const u64 aBase[] = { + UINT64_C(0x8000000000000000), /* 0: 1.0e+0 << 63 */ + UINT64_C(0xa000000000000000), /* 1: 1.0e+1 << 60 */ + UINT64_C(0xc800000000000000), /* 2: 1.0e+2 << 57 */ + UINT64_C(0xfa00000000000000), /* 3: 1.0e+3 << 54 */ + UINT64_C(0x9c40000000000000), /* 4: 1.0e+4 << 50 */ + UINT64_C(0xc350000000000000), /* 5: 1.0e+5 << 47 */ + UINT64_C(0xf424000000000000), /* 6: 1.0e+6 << 44 */ + UINT64_C(0x9896800000000000), /* 7: 1.0e+7 << 40 */ + UINT64_C(0xbebc200000000000), /* 8: 1.0e+8 << 37 */ + UINT64_C(0xee6b280000000000), /* 9: 1.0e+9 << 34 */ + UINT64_C(0x9502f90000000000), /* 10: 1.0e+10 << 30 */ + UINT64_C(0xba43b74000000000), /* 11: 1.0e+11 << 27 */ + UINT64_C(0xe8d4a51000000000), /* 12: 1.0e+12 << 24 */ + UINT64_C(0x9184e72a00000000), /* 13: 1.0e+13 << 20 */ + UINT64_C(0xb5e620f480000000), /* 14: 1.0e+14 << 17 */ + UINT64_C(0xe35fa931a0000000), /* 15: 1.0e+15 << 14 */ + UINT64_C(0x8e1bc9bf04000000), /* 16: 1.0e+16 << 10 */ + UINT64_C(0xb1a2bc2ec5000000), /* 17: 1.0e+17 << 7 */ + UINT64_C(0xde0b6b3a76400000), /* 18: 1.0e+18 << 4 */ + UINT64_C(0x8ac7230489e80000), /* 19: 1.0e+19 >> 0 */ + UINT64_C(0xad78ebc5ac620000), /* 20: 1.0e+20 >> 3 */ + UINT64_C(0xd8d726b7177a8000), /* 21: 1.0e+21 >> 6 */ + UINT64_C(0x878678326eac9000), /* 22: 1.0e+22 >> 10 */ + UINT64_C(0xa968163f0a57b400), /* 23: 1.0e+23 >> 13 */ + UINT64_C(0xd3c21bcecceda100), /* 24: 1.0e+24 >> 16 */ + UINT64_C(0x84595161401484a0), /* 25: 1.0e+25 >> 20 */ + UINT64_C(0xa56fa5b99019a5c8), /* 26: 1.0e+26 >> 23 */ + }; + static const u64 aScale[] = { + UINT64_C(0x8049a4ac0c5811ae), /* 0: 1.0e-351 << 1229 */ + UINT64_C(0xcf42894a5dce35ea), /* 1: 1.0e-324 << 1140 */ + UINT64_C(0xa76c582338ed2621), /* 2: 1.0e-297 << 1050 */ + UINT64_C(0x873e4f75e2224e68), /* 3: 1.0e-270 << 960 */ + UINT64_C(0xda7f5bf590966848), /* 4: 1.0e-243 << 871 */ + UINT64_C(0xb080392cc4349dec), /* 5: 1.0e-216 << 781 */ + UINT64_C(0x8e938662882af53e), /* 6: 1.0e-189 << 691 */ + UINT64_C(0xe65829b3046b0afa), /* 7: 1.0e-162 << 602 */ + UINT64_C(0xba121a4650e4ddeb), /* 8: 1.0e-135 << 512 */ + UINT64_C(0x964e858c91ba2655), /* 9: 1.0e-108 << 422 */ + UINT64_C(0xf2d56790ab41c2a2), /* 10: 1.0e-81 << 333 */ + UINT64_C(0xc428d05aa4751e4c), /* 11: 1.0e-54 << 243 */ + UINT64_C(0x9e74d1b791e07e48), /* 12: 1.0e-27 << 153 */ + UINT64_C(0xcccccccccccccccc), /* 13: 1.0e-1 << 67 (special case) */ + UINT64_C(0xcecb8f27f4200f3a), /* 14: 1.0e+27 >> 26 */ + UINT64_C(0xa70c3c40a64e6c51), /* 15: 1.0e+54 >> 116 */ + UINT64_C(0x86f0ac99b4e8dafd), /* 16: 1.0e+81 >> 206 */ + UINT64_C(0xda01ee641a708de9), /* 17: 1.0e+108 >> 295 */ + UINT64_C(0xb01ae745b101e9e4), /* 18: 1.0e+135 >> 385 */ + UINT64_C(0x8e41ade9fbebc27d), /* 19: 1.0e+162 >> 475 */ + UINT64_C(0xe5d3ef282a242e81), /* 20: 1.0e+189 >> 564 */ + UINT64_C(0xb9a74a0637ce2ee1), /* 21: 1.0e+216 >> 654 */ + UINT64_C(0x95f83d0a1fb69cd9), /* 22: 1.0e+243 >> 744 */ + UINT64_C(0xf24a01a73cf2dccf), /* 23: 1.0e+270 >> 833 */ + UINT64_C(0xc3b8358109e84f07), /* 24: 1.0e+297 >> 923 */ + UINT64_C(0x9e19db92b4e31ba9), /* 25: 1.0e+324 >> 1013 */ + }; + static const unsigned int aScaleLo[] = { + 0x205b896d, /* 0: 1.0e-351 << 1229 */ + 0x52064cad, /* 1: 1.0e-324 << 1140 */ + 0xaf2af2b8, /* 2: 1.0e-297 << 1050 */ + 0x5a7744a7, /* 3: 1.0e-270 << 960 */ + 0xaf39a475, /* 4: 1.0e-243 << 871 */ + 0xbd8d794e, /* 5: 1.0e-216 << 781 */ + 0x547eb47b, /* 6: 1.0e-189 << 691 */ + 0x0cb4a5a3, /* 7: 1.0e-162 << 602 */ + 0x92f34d62, /* 8: 1.0e-135 << 512 */ + 0x3a6a07f9, /* 9: 1.0e-108 << 422 */ + 0xfae27299, /* 10: 1.0e-81 << 333 */ + 0xaa97e14c, /* 11: 1.0e-54 << 243 */ + 0x775ea265, /* 12: 1.0e-27 << 153 */ + 0xcccccccc, /* 13: 1.0e-1 << 67 (special case) */ + 0x00000000, /* 14: 1.0e+27 >> 26 */ + 0x999090b6, /* 15: 1.0e+54 >> 116 */ + 0x69a028bb, /* 16: 1.0e+81 >> 206 */ + 0xe80e6f48, /* 17: 1.0e+108 >> 295 */ + 0x5ec05dd0, /* 18: 1.0e+135 >> 385 */ + 0x14588f14, /* 19: 1.0e+162 >> 475 */ + 0x8f1668c9, /* 20: 1.0e+189 >> 564 */ + 0x6d953e2c, /* 21: 1.0e+216 >> 654 */ + 0x4abdaf10, /* 22: 1.0e+243 >> 744 */ + 0xbc633b39, /* 23: 1.0e+270 >> 833 */ + 0x0a862f81, /* 24: 1.0e+297 >> 923 */ + 0x6c07a2c2, /* 25: 1.0e+324 >> 1013 */ + }; + int g, n; + u64 s, x; + u32 lo; + + assert( p>=POWERSOF10_FIRST && p<=POWERSOF10_LAST ); + if( p<0 ){ + if( p==(-1) ){ + *pLo = aScaleLo[13]; + return aScale[13]; + } + g = p/27; + n = p%27; + if( n ){ + g--; + n += 27; + } + }else if( p<27 ){ + *pLo = 0; + return aBase[p]; + }else{ + g = p/27; + n = p%27; + } + s = aScale[g+13]; + if( n==0 ){ + *pLo = aScaleLo[g+13]; + return s; + } + x = sqlite3Multiply160(s,aScaleLo[g+13],aBase[n],&lo); + if( (U64_BIT(63) & x)==0 ){ + x = x<<1 | ((lo>>31)&1); + lo = (lo<<1) | 1; + } + *pLo = lo; + return x; +} + +/* +** pow10to2(x) computes floor(log2(pow(10,x))). +** pow2to10(y) computes floor(log10(pow(2,y))). +** +** Conceptually, pow10to2(p) converts a base-10 exponent p into +** a corresponding base-2 exponent, and pow2to10(e) converts a base-2 +** exponent into a base-10 exponent. +** +** The conversions are based on the observation that: +** +** ln(10.0)/ln(2.0) == 108853/32768 (approximately) +** ln(2.0)/ln(10.0) == 78913/262144 (approximately) +** +** These ratios are approximate, but they are accurate to 5 digits, +** which is close enough for the usage here. Right-shift is used +** for division so that rounding of negative numbers happens in the +** right direction. +*/ +static int pwr10to2(int p){ return (p*108853) >> 15; } +static int pwr2to10(int p){ return (p*78913) >> 18; } + +/* +** Count leading zeros for a 64-bit unsigned integer. +*/ +static int countLeadingZeros(u64 m){ +#if (defined(__GNUC__) || defined(__clang__)) \ + && !defined(SQLITE_DISABLE_INTRINSIC) + return __builtin_clzll(m); +#else + int n = 0; + if( m <= 0x00000000ffffffffULL) { n += 32; m <<= 32; } + if( m <= 0x0000ffffffffffffULL) { n += 16; m <<= 16; } + if( m <= 0x00ffffffffffffffULL) { n += 8; m <<= 8; } + if( m <= 0x0fffffffffffffffULL) { n += 4; m <<= 4; } + if( m <= 0x3fffffffffffffffULL) { n += 2; m <<= 2; } + if( m <= 0x7fffffffffffffffULL) { n += 1; } + return n; +#endif +} + +/* +** Given m and e, which represent a quantity r == m*pow(2,e), +** return values *pD and *pP such that r == (*pD)*pow(10,*pP), +** approximately. *pD should contain at least n significant digits. +** +** The input m is required to have its highest bit set. In other words, +** m should be left-shifted, and e decremented, to maximize the value of m. +*/ +static void sqlite3Fp2Convert10(u64 m, int e, int n, u64 *pD, int *pP){ + int p; + u64 h, d1; + u32 d2; + assert( n>=1 && n<=18 ); + p = n - 1 - pwr2to10(e+63); + h = sqlite3Multiply128(m, powerOfTen(p,&d2), &d1); + assert( -(e + pwr10to2(p) + 2) >= 0 ); + assert( -(e + pwr10to2(p) + 1) <= 63 ); + if( n==18 ){ + h >>= -(e + pwr10to2(p) + 2); + *pD = (h + ((h<<1)&2))>>1; + }else{ + *pD = h >> -(e + pwr10to2(p) + 1); + } + *pP = -p; +} + +/* +** Return an IEEE754 floating point value that approximates d*pow(10,p). +** +** The (current) algorithm is adapted from the work of Ross Cox at +** https://github.com/rsc/fpfmt +*/ +static double sqlite3Fp10Convert2(u64 d, int p){ + int b, lp, e, adj, s; + u32 pwr10l, mid1; + u64 pwr10h, x, hi, lo, sticky, u, m; + double r; + if( pPOWERSOF10_LAST ) return INFINITY; + b = 64 - countLeadingZeros(d); + lp = pwr10to2(p); + e = 53 - b - lp; + if( e > 1074 ){ + if( e>=1130 ) return 0.0; + e = 1074; + } + s = -(e-(64-b) + lp + 3); + pwr10h = powerOfTen(p, &pwr10l); + if( pwr10l!=0 ){ + pwr10h++; + pwr10l = ~pwr10l; + } + x = d<<(64-b); + hi = sqlite3Multiply128(x,pwr10h,&lo); + mid1 = lo>>32; + sticky = 1; + if( (hi & (U64_BIT(s)-1))==0 ) { + u32 mid2 = sqlite3Multiply128(x,((u64)pwr10l)<<32,&lo)>>32; + sticky = (mid1-mid2 > 1); + hi -= mid1 < mid2; + } + u = (hi>>s) | sticky; + adj = (u >= U64_BIT(55)-2); + if( adj ){ + u = (u>>adj) | (u&1); + e -= adj; + } + m = (u + 1 + ((u>>2)&1)) >> 2; + if( e<=(-972) ) return INFINITY; + if((m & U64_BIT(52)) != 0){ + m = (m & ~U64_BIT(52)) | ((u64)(1075-e)<<52); + } + memcpy(&r,&m,8); + return r; } /* ** The string z[] is an text representation of a real number. ** Convert this string to a double and write it into *pResult. ** -** The string z[] is length bytes in length (bytes, not characters) and -** uses the encoding enc. The string is not necessarily zero-terminated. +** z[] must be UTF-8 and zero-terminated. ** -** Return TRUE if the result is a valid real number (or integer) and FALSE -** if the string is empty or contains extraneous text. More specifically -** return -** 1 => The input string is a pure integer -** 2 or more => The input has a decimal point or eNNN clause -** 0 or less => The input string is not a valid number -** -1 => Not a valid number, but has a valid prefix which -** includes a decimal point and/or an eNNN clause +** Return positive if the result is a valid real number (or integer) and +** zero or negative if the string is empty or contains extraneous text. +** Lower bits of the return value contain addition information about the +** parse: ** -** Valid numbers are in one of these formats: +** bit 0 => Set if any prefix of the input is valid. Clear if +** there is no prefix of the input that can be seen as +** a valid floating point number. +** bit 1 => Set if the input contains a decimal point or eNNN +** clause. Zero if the input is an integer. +** bit 2 => The input is exactly 0.0, not an underflow from +** some value near zero. +** bit 3 => Set if there are more than about 19 significant +** digits in the input. +** +** If the input contains a syntax error but begins with text that might +** be a valid number of some kind, then the result is negative. The +** result is only zero if no prefix of the input could be interpreted as +** a number. +** +** Leading and trailing whitespace is ignored. Valid numbers are in +** one of the formats below: ** ** [+-]digits[E[+-]digits] ** [+-]digits.[digits][E[+-]digits] ** [+-].digits[E[+-]digits] ** -** Leading and trailing whitespace is ignored for the purpose of determining -** validity. -** -** If some prefix of the input string is a valid number, this routine -** returns FALSE but it still converts the prefix and writes the result -** into *pResult. +** Algorithm sketch: Compute an unsigned 64-bit integer s and a base-10 +** exponent d such that the value encoding by the input is s*pow(10,d). +** Then invoke sqlite3Fp10Convert2() to calculated the closest possible +** IEEE754 double. The sign is added back afterwards, if the input string +** starts with a "-". The use of an unsigned 64-bit s mantissa means that +** only about the first 19 significant digits of the input can contribute +** to the result. This can result in suboptimal rounding decisions when +** correct rounding requires more than 19 input digits. For example, +** this routine renders "3500000000000000.2500001" as +** 3500000000000000.0 instead of 3500000000000000.5 because the decision +** to round up instead of using banker's rounding to round down is determined +** by the 23rd significant digit, which this routine ignores. It is not +** possible to do better without some kind of BigNum. */ -#if defined(_MSC_VER) -#pragma warning(disable : 4756) -#endif -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ +SQLITE_PRIVATE int sqlite3AtoF(const char *zIn, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT - int incr; - const char *zEnd; - /* sign * significand * (10 ^ (esign * exponent)) */ - int sign = 1; /* sign of significand */ - u64 s = 0; /* significand */ - int d = 0; /* adjust exponent for shifting decimal point */ - int esign = 1; /* sign of exponent */ - int e = 0; /* exponent */ - int eValid = 1; /* True exponent is either not used or is well-formed */ - int nDigit = 0; /* Number of digits processed */ - int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ - u64 s2; /* round-tripped significand */ - double rr[2]; + const unsigned char *z = (const unsigned char*)zIn; + int neg = 0; /* True for a negative value */ + u64 s = 0; /* mantissa */ + int d = 0; /* Value is s * pow(10,d) */ + int mState = 0; /* 1: digit seen 2: fp 4: hard-zero */ + unsigned v; /* Value of a single digit */ - assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); - *pResult = 0.0; /* Default return value, in case of an error */ - if( length==0 ) return 0; - - if( enc==SQLITE_UTF8 ){ - incr = 1; - zEnd = z + length; - }else{ - int i; - incr = 2; - length &= ~1; - assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); - testcase( enc==SQLITE_UTF16LE ); - testcase( enc==SQLITE_UTF16BE ); - for(i=3-enc; i=zEnd ) return 0; - - /* get sign of significand */ - if( *z=='-' ){ - sign = -1; - z+=incr; - }else if( *z=='+' ){ - z+=incr; - } - - /* copy max significant digits to significand */ - while( z=((LARGEST_UINT64-9)/10) ){ - /* skip non-significant significand digits - ** (increase exponent by d to shift decimal left) */ - while( z=(LARGEST_UINT64-9)/10 ){ + mState = 9; + while( sqlite3Isdigit(z[0]) ){ z++; d++; } + break; + } } + }else if( z[0]=='-' ){ + neg = 1; + z++; + if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part; + }else if( z[0]=='+' ){ + z++; + if( (v = (unsigned)z[0] - '0')<10 ) goto parse_integer_part; + }else if( sqlite3Isspace(z[0]) ){ + do{ z++; }while( sqlite3Isspace(z[0]) ); + goto start_of_text; + }else{ + s = 0; } - if( z>=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ - z+=incr; - eType++; - /* copy digits from after decimal to significand - ** (decrease exponent by d to shift decimal right) */ - while( z=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ - z+=incr; - eValid = 0; - eType++; - - /* This branch is needed to avoid a (harmless) buffer overread. The - ** special comment alerts the mutation tester that the correct answer - ** is obtained even if the branch is omitted */ - if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/ + int esign; + z++; /* get sign of exponent */ if( *z=='-' ){ esign = -1; - z+=incr; - }else if( *z=='+' ){ - z+=incr; + z++; + }else{ + esign = +1; + if( *z=='+' ){ + z++; + } } /* copy digits to exponent */ - while( z0 && s<((LARGEST_UINT64-0x7ff)/10) ){ - s *= 10; - e--; - } - while( e<0 && (s%10)==0 ){ - s /= 10; - e++; - } - - rr[0] = (double)s; - assert( sizeof(s2)==sizeof(rr[0]) ); -#ifdef SQLITE_DEBUG - rr[1] = 18446744073709549568.0; - memcpy(&s2, &rr[1], sizeof(s2)); - assert( s2==0x43efffffffffffffLL ); -#endif - /* Largest double that can be safely converted to u64 - ** vvvvvvvvvvvvvvvvvvvvvv */ - if( rr[0]<=18446744073709549568.0 ){ - s2 = (u64)rr[0]; - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); + *pResult = 0.0; + mState |= 4; }else{ - rr[1] = 0.0; + *pResult = sqlite3Fp10Convert2(s,d); } - assert( rr[1]<=1.0e-10*rr[0] ); /* Equal only when rr[0]==0.0 */ - - if( e>0 ){ - while( e>=100 ){ - e -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( e>=10 ){ - e -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( e>=1 ){ - e -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } - }else{ - while( e<=-100 ){ - e += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( e<=-10 ){ - e += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( e<=-1 ){ - e += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } - } - *pResult = rr[0]+rr[1]; - if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300; - if( sign<0 ) *pResult = -*pResult; + if( neg ) *pResult = -*pResult; assert( !sqlite3IsNaN(*pResult) ); -atof_return: /* return true if number and no extra non-whitespace characters after */ - if( z==zEnd && nDigit>0 && eValid && eType>0 ){ - return eType; - }else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){ - return -1; - }else{ - return 0; + if( z[0]==0 ){ + return mState; } + if( sqlite3Isspace(z[0]) ){ + do{ z++; }while( sqlite3Isspace(*z) ); + if( z[0]==0 ){ + return mState; + } + } + return 0xfffffff0 | mState; #else - return !sqlite3Atoi64(z, pResult, length, enc); + return sqlite3Atoi64(z, pResult, strlen(z), SQLITE_UTF8)==0; #endif /* SQLITE_OMIT_FLOATING_POINT */ } -#if defined(_MSC_VER) -#pragma warning(default : 4756) + +/* +** Digit pairs used to convert a U64 or I64 into text, two digits +** at a time. +*/ +static const union { + char a[201]; + short int forceAlignment; +} sqlite3DigitPairs = { + "00010203040506070809" + "10111213141516171819" + "20212223242526272829" + "30313233343536373839" + "40414243444546474849" + "50515253545556575859" + "60616263646566676869" + "70717273747576777879" + "80818283848586878889" + "90919293949596979899" +}; + +/* +** ARMv6, ARMv7, PPC32 are known to not support hardware u64 division. +*/ +#if (defined(__arm__) && !defined(__aarch64__)) || \ + (defined(__ppc__) && !defined(__ppc64__)) +# define SQLITE_AVOID_U64_DIVIDE 1 #endif +#ifdef SQLITE_AVOID_U64_DIVIDE +/* +** Render an unsigned 64-bit integer as text onto the end of a 2-byte +** aligned buffer that is SQLITE_U64_DIGIT+1 bytes long. The last byte +** of the buffer will be filled with a \000 byte. +** +** Return the index into the buffer of the first byte. +** +** This routine is used on platforms where u64-division is slow because +** it is not available in hardware and has to be emulated in software. +** It seeks to minimize the number of u64 divisions and use u32 divisions +** instead. It is slower on platforms that have hardware u64 division, +** but much faster on platforms that do not. +*/ +static int sqlite3UInt64ToText(u64 v, char *zOut){ + u32 x32, kk; + int i; + zOut[SQLITE_U64_DIGITS] = 0; + i = SQLITE_U64_DIGITS; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[0]) ); + assert( TWO_BYTE_ALIGNMENT(zOut) ); + while( (v>>32)!=0 ){ + u32 y, x0, x1, y0, y1; + x32 = v % 100000000; + v = v / 100000000; + y = x32 % 10000; + x32 /= 10000; + x1 = x32 / 100; + x0 = x32 % 100; + y1 = y / 100; + y0 = y % 100; + assert( i>=8 ); + i -= 8; + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[x1*2]; + *(u16*)(&zOut[i+2]) = *(u16*)&sqlite3DigitPairs.a[x0*2]; + *(u16*)(&zOut[i+4]) = *(u16*)&sqlite3DigitPairs.a[y1*2]; + *(u16*)(&zOut[i+6]) = *(u16*)&sqlite3DigitPairs.a[y0*2]; + } + x32 = v; + while( x32>=10 ){ + kk = x32 % 100; + x32 = x32 / 100; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk*2]) ); + assert( i>=2 ); + i -= 2; + assert( TWO_BYTE_ALIGNMENT(&zOut[i]) ); + *(u16*)(&zOut[i]) = *(u16*)&sqlite3DigitPairs.a[kk*2]; + } + if( x32 ){ + assert( i>0 ); + zOut[--i] = x32 + '0'; + } + return i; +} +#endif /* defined(SQLITE_AVOID_U64_DIVIDE) */ + /* ** Render an signed 64-bit integer as text. Store the result in zOut[] and ** return the length of the string that was stored, in bytes. The value @@ -36596,23 +37410,39 @@ atof_return: SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){ int i; u64 x; - char zTemp[22]; - if( v<0 ){ - x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; - }else{ + union { + char a[SQLITE_U64_DIGITS+1]; + u16 forceAlignment; + } u; + if( v>0 ){ x = v; + }else if( v==0 ){ + zOut[0] = '0'; + zOut[1] = 0; + return 1; + }else{ + x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v; } - i = sizeof(zTemp)-2; - zTemp[sizeof(zTemp)-1] = 0; - while( 1 /*exit-by-break*/ ){ - zTemp[i] = (x%10) + '0'; - x = x/10; - if( x==0 ) break; - i--; - }; - if( v<0 ) zTemp[--i] = '-'; - memcpy(zOut, &zTemp[i], sizeof(zTemp)-i); - return sizeof(zTemp)-1-i; +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(x, u.a); +#else + i = sizeof(u.a)-1; + u.a[i] = 0; + while( x>=10 ){ + int kk = (x%100)*2; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&u.a[i-2]) ); + *(u16*)(&u.a[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; + i -= 2; + x /= 100; + } + if( x ){ + u.a[--i] = x + '0'; + } +#endif /* SQLITE_AVOID_U64_DIVIDE */ + if( v<0 ) u.a[--i] = '-'; + memcpy(zOut, &u.a[i], sizeof(u.a)-i); + return sizeof(u.a)-1-i; } /* @@ -36666,8 +37496,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc int incr; u64 u = 0; int neg = 0; /* assume positive */ - int i; - int c = 0; + int i, j; + unsigned int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ int rc; /* Baseline return code */ const char *zStart; @@ -36695,8 +37525,8 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc } zStart = zNum; while( zNum='0' && c<='9'; i+=incr){ - u = u*10 + c - '0'; + for(i=0; &zNum[i]19*incr ? 1 : compare2pow63(zNum, incr); - if( c<0 ){ + j = i>19*incr ? 1 : compare2pow63(zNum, incr); + if( j<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); return rc; }else{ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; - if( c>0 ){ + if( j>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ return 2; }else{ @@ -36869,7 +37699,7 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ ** representation. ** ** If iRound<=0 then round to -iRound significant digits to the -** the left of the decimal point, or to a maximum of mxRound total +** the right of the decimal point, or to a maximum of mxRound total ** significant digits. ** ** If iRound>0 round to min(iRound,mxRound) significant digits total. @@ -36882,13 +37712,14 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){ ** The p->z[] array is *not* zero-terminated. */ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ - int i; - u64 v; - int e, exp = 0; - double rr[2]; + int i; /* Index into zBuf[] where to put next character */ + int n; /* Number of digits */ + u64 v; /* mantissa */ + int e, exp = 0; /* Base-2 and base-10 exponent */ + char *zBuf; /* Local alias for p->zBuf */ + char *z; /* Local alias for p->z */ p->isSpecial = 0; - p->z = p->zBuf; assert( mxRound>0 ); /* Convert negative numbers to positive. Deal with Infinity, 0.0, and @@ -36906,78 +37737,100 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou p->sign = '+'; } memcpy(&v,&r,8); - e = v>>52; - if( (e&0x7ff)==0x7ff ){ + e = (v>>52)&0x7ff; + if( e==0x7ff ){ p->isSpecial = 1 + (v!=0x7ff0000000000000LL); p->n = 0; p->iDP = 0; + p->z = p->zBuf; return; } - - /* Multiply r by powers of ten until it lands somewhere in between - ** 1.0e+19 and 1.0e+17. - ** - ** Use Dekker-style double-double computation to increase the - ** precision. - ** - ** The error terms on constants like 1.0e+100 computed using the - ** decimal extension, for example as follows: - ** - ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100))); - */ - rr[0] = r; - rr[1] = 0.0; - if( rr[0]>9.223372036854774784e+18 ){ - while( rr[0]>9.223372036854774784e+118 ){ - exp += 100; - dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117); - } - while( rr[0]>9.223372036854774784e+28 ){ - exp += 10; - dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27); - } - while( rr[0]>9.223372036854774784e+18 ){ - exp += 1; - dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18); - } + v &= 0x000fffffffffffffULL; + if( e==0 ){ + int nn = countLeadingZeros(v); + v <<= nn; + e = -1074 - nn; }else{ - while( rr[0]<9.223372036854774784e-83 ){ - exp -= 100; - dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83); - } - while( rr[0]<9.223372036854774784e+07 ){ - exp -= 10; - dekkerMul2(rr, 1.0e+10, 0.0); - } - while( rr[0]<9.22337203685477478e+17 ){ - exp -= 1; - dekkerMul2(rr, 1.0e+01, 0.0); - } + v = (v<<11) | U64_BIT(63); + e -= 1086; } - v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1]; + sqlite3Fp2Convert10(v, e, (iRound<=0||iRound>=18)?18:iRound+1, &v, &exp); - /* Extract significant digits. */ - i = sizeof(p->zBuf)-1; + /* Extract significant digits, start at the right-most slot in p->zBuf + ** and working back to the right. "i" keeps track of the next slot in + ** which to store a digit. */ + assert( sizeof(p->zBuf)==SQLITE_U64_DIGITS+1 ); assert( v>0 ); - while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; } - assert( i>=0 && izBuf)-1 ); - p->n = sizeof(p->zBuf) - 1 - i; - assert( p->n>0 ); - assert( p->nzBuf) ); - p->iDP = p->n + exp; + zBuf = p->zBuf; +#ifdef SQLITE_AVOID_U64_DIVIDE + i = sqlite3UInt64ToText(v, zBuf); +#else + i = SQLITE_U64_DIGITS; + while( v>=10 ){ + int kk = (v%100)*2; + assert( TWO_BYTE_ALIGNMENT(&sqlite3DigitPairs.a[kk]) ); + assert( TWO_BYTE_ALIGNMENT(&zBuf[i]) ); + assert( i-2>=0 ); + *(u16*)(&zBuf[i-2]) = *(u16*)&sqlite3DigitPairs.a[kk]; + i -= 2; + v /= 100; + } + if( v ){ + assert( v<10 ); + assert( i>0 ); + zBuf[--i] = v + '0'; + } +#endif /* SQLITE_AVOID_U64_DIVIDE */ + assert( i>=0 && i0 ); + assert( n<=SQLITE_U64_DIGITS ); + p->iDP = n + exp; if( iRound<=0 ){ iRound = p->iDP - iRound; - if( iRound==0 && p->zBuf[i+1]>='5' ){ + if( iRound==0 && zBuf[i]>='5' ){ iRound = 1; - p->zBuf[i--] = '0'; - p->n++; + zBuf[--i] = '0'; + n++; p->iDP++; } } - if( iRound>0 && (iRoundn || p->n>mxRound) ){ - char *z = &p->zBuf[i+1]; + z = &zBuf[i]; /* z points to the first digit */ + if( iRound>0 && (iRoundmxRound) ){ if( iRound>mxRound ) iRound = mxRound; - p->n = iRound; + if( iRound==17 ){ + /* If the precision is exactly 17, which only happens with the "!" + ** flag (ex: "%!.17g") then try to reduce the precision if that + ** yields text that will round-trip to the original floating-point. + ** value. Thus, for exaple, 49.47 will render as 49.47, rather than + ** as 49.469999999999999. */ + if( z[15]=='9' && z[14]=='9' ){ + int jj, kk; + u64 v2; + for(jj=14; jj>0 && z[jj-1]=='9'; jj--){} + if( jj==0 ){ + v2 = 1; + }else{ + v2 = z[0] - '0'; + for(kk=1; kkiDP>=n || (z[15]=='0' && z[14]=='0' && z[13]=='0') ){ + int jj, kk; + u64 v2; + assert( z[0]!='0' ); + for(jj=13; z[jj-1]=='0'; jj--){} + v2 = z[0] - '0'; + for(kk=1; kk='5' ){ int j = iRound-1; while( 1 /*exit-by-break*/ ){ @@ -36985,8 +37838,9 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou if( z[j]<='9' ) break; z[j] = '0'; if( j==0 ){ - p->z[i--] = '1'; - p->n++; + z--; + z[0] = '1'; + n++; p->iDP++; break; }else{ @@ -36995,13 +37849,13 @@ SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRou } } } - p->z = &p->zBuf[i+1]; - assert( i+p->n < sizeof(p->zBuf) ); - assert( p->n>0 ); - while( p->z[p->n-1]=='0' ){ - p->n--; - assert( p->n>0 ); + assert( n>0 ); + while( z[n-1]=='0' ){ + n--; + assert( n>0 ); } + p->n = n; + p->z = z; } /* @@ -38066,10 +38920,10 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"), /* 45 */ "IdxLT" OpHelp("key=r[P3@P4]"), /* 46 */ "IdxGE" OpHelp("key=r[P3@P4]"), - /* 47 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), - /* 48 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), - /* 49 */ "Program" OpHelp(""), - /* 50 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 47 */ "IFindKey" OpHelp(""), + /* 48 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"), + /* 49 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"), + /* 50 */ "Program" OpHelp(""), /* 51 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"), /* 52 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"), /* 53 */ "Ne" OpHelp("IF r[P3]!=r[P1]"), @@ -38079,49 +38933,49 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ /* 57 */ "Lt" OpHelp("IF r[P3]=r[P1]"), /* 59 */ "ElseEq" OpHelp(""), - /* 60 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), - /* 61 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), - /* 62 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), - /* 63 */ "IncrVacuum" OpHelp(""), - /* 64 */ "VNext" OpHelp(""), - /* 65 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), - /* 66 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), - /* 67 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), - /* 68 */ "Return" OpHelp(""), - /* 69 */ "EndCoroutine" OpHelp(""), - /* 70 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), - /* 71 */ "Halt" OpHelp(""), - /* 72 */ "Integer" OpHelp("r[P2]=P1"), - /* 73 */ "Int64" OpHelp("r[P2]=P4"), - /* 74 */ "String" OpHelp("r[P2]='P4' (len=P1)"), - /* 75 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), - /* 76 */ "Null" OpHelp("r[P2..P3]=NULL"), - /* 77 */ "SoftNull" OpHelp("r[P1]=NULL"), - /* 78 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), - /* 79 */ "Variable" OpHelp("r[P2]=parameter(P1)"), - /* 80 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), - /* 81 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), - /* 82 */ "SCopy" OpHelp("r[P2]=r[P1]"), - /* 83 */ "IntCopy" OpHelp("r[P2]=r[P1]"), - /* 84 */ "FkCheck" OpHelp(""), - /* 85 */ "ResultRow" OpHelp("output=r[P1@P2]"), - /* 86 */ "CollSeq" OpHelp(""), - /* 87 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), - /* 88 */ "RealAffinity" OpHelp(""), - /* 89 */ "Cast" OpHelp("affinity(r[P1])"), - /* 90 */ "Permutation" OpHelp(""), - /* 91 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), - /* 92 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), - /* 93 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), - /* 94 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), - /* 95 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), - /* 96 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), - /* 97 */ "Affinity" OpHelp("affinity(r[P1@P2])"), - /* 98 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), - /* 99 */ "Count" OpHelp("r[P2]=count()"), - /* 100 */ "ReadCookie" OpHelp(""), - /* 101 */ "SetCookie" OpHelp(""), - /* 102 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"), + /* 60 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"), + /* 61 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"), + /* 62 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"), + /* 63 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"), + /* 64 */ "IncrVacuum" OpHelp(""), + /* 65 */ "VNext" OpHelp(""), + /* 66 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"), + /* 67 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"), + /* 68 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"), + /* 69 */ "Return" OpHelp(""), + /* 70 */ "EndCoroutine" OpHelp(""), + /* 71 */ "HaltIfNull" OpHelp("if r[P3]=null halt"), + /* 72 */ "Halt" OpHelp(""), + /* 73 */ "Integer" OpHelp("r[P2]=P1"), + /* 74 */ "Int64" OpHelp("r[P2]=P4"), + /* 75 */ "String" OpHelp("r[P2]='P4' (len=P1)"), + /* 76 */ "BeginSubrtn" OpHelp("r[P2]=NULL"), + /* 77 */ "Null" OpHelp("r[P2..P3]=NULL"), + /* 78 */ "SoftNull" OpHelp("r[P1]=NULL"), + /* 79 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"), + /* 80 */ "Variable" OpHelp("r[P2]=parameter(P1)"), + /* 81 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"), + /* 82 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"), + /* 83 */ "SCopy" OpHelp("r[P2]=r[P1]"), + /* 84 */ "IntCopy" OpHelp("r[P2]=r[P1]"), + /* 85 */ "FkCheck" OpHelp(""), + /* 86 */ "ResultRow" OpHelp("output=r[P1@P2]"), + /* 87 */ "CollSeq" OpHelp(""), + /* 88 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"), + /* 89 */ "RealAffinity" OpHelp(""), + /* 90 */ "Cast" OpHelp("affinity(r[P1])"), + /* 91 */ "Permutation" OpHelp(""), + /* 92 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"), + /* 93 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"), + /* 94 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"), + /* 95 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"), + /* 96 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"), + /* 97 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"), + /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"), + /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"), + /* 100 */ "Count" OpHelp("r[P2]=count()"), + /* 101 */ "ReadCookie" OpHelp(""), + /* 102 */ "SetCookie" OpHelp(""), /* 103 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"), /* 104 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"), /* 105 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), - /* 162 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), - /* 163 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 164 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), - /* 165 */ "AggValue" OpHelp("r[P3]=value N=P2"), - /* 166 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), - /* 167 */ "Expire" OpHelp(""), - /* 168 */ "CursorLock" OpHelp(""), - /* 169 */ "CursorUnlock" OpHelp(""), - /* 170 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), - /* 171 */ "VBegin" OpHelp(""), - /* 172 */ "VCreate" OpHelp(""), - /* 173 */ "VDestroy" OpHelp(""), - /* 174 */ "VOpen" OpHelp(""), - /* 175 */ "VCheck" OpHelp(""), - /* 176 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), - /* 177 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), - /* 178 */ "VRename" OpHelp(""), - /* 179 */ "Pagecount" OpHelp(""), - /* 180 */ "MaxPgcnt" OpHelp(""), - /* 181 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), - /* 182 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), - /* 183 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), - /* 184 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), - /* 185 */ "Trace" OpHelp(""), - /* 186 */ "CursorHint" OpHelp(""), - /* 187 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), - /* 188 */ "Noop" OpHelp(""), - /* 189 */ "Explain" OpHelp(""), - /* 190 */ "Abortable" OpHelp(""), + /* 155 */ "DropIndex" OpHelp(""), + /* 156 */ "DropTrigger" OpHelp(""), + /* 157 */ "IntegrityCk" OpHelp(""), + /* 158 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"), + /* 159 */ "Param" OpHelp(""), + /* 160 */ "FkCounter" OpHelp("fkctr[P1]+=P2"), + /* 161 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"), + /* 162 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"), + /* 163 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"), + /* 164 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 165 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"), + /* 166 */ "AggValue" OpHelp("r[P3]=value N=P2"), + /* 167 */ "AggFinal" OpHelp("accum=r[P1] N=P2"), + /* 168 */ "Expire" OpHelp(""), + /* 169 */ "CursorLock" OpHelp(""), + /* 170 */ "CursorUnlock" OpHelp(""), + /* 171 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"), + /* 172 */ "VBegin" OpHelp(""), + /* 173 */ "VCreate" OpHelp(""), + /* 174 */ "VDestroy" OpHelp(""), + /* 175 */ "VOpen" OpHelp(""), + /* 176 */ "VCheck" OpHelp(""), + /* 177 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"), + /* 178 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"), + /* 179 */ "VRename" OpHelp(""), + /* 180 */ "Pagecount" OpHelp(""), + /* 181 */ "MaxPgcnt" OpHelp(""), + /* 182 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"), + /* 183 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"), + /* 184 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"), + /* 185 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"), + /* 186 */ "Trace" OpHelp(""), + /* 187 */ "CursorHint" OpHelp(""), + /* 188 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"), + /* 189 */ "Noop" OpHelp(""), + /* 190 */ "Explain" OpHelp(""), + /* 191 */ "Abortable" OpHelp(""), }; return azName[i]; } @@ -38240,7 +39095,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ ** Debugging logic */ -/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */ +/* SQLITE_KV_TRACE() is used for tracing calls to kvrecord routines. */ #if 0 #define SQLITE_KV_TRACE(X) printf X #else @@ -38254,7 +39109,6 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){ #define SQLITE_KV_LOG(X) #endif - /* ** Forward declaration of objects used by this VFS implementation */ @@ -38262,6 +39116,11 @@ typedef struct KVVfsFile KVVfsFile; /* A single open file. There are only two files represented by this ** VFS - the database and the rollback journal. +** +** Maintenance reminder: if this struct changes in any way, the JSON +** rendering of its structure must be updated in +** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary +** compatibility concerns, so it does not need an iVersion member. */ struct KVVfsFile { sqlite3_file base; /* IO methods */ @@ -38311,7 +39170,7 @@ static int kvvfsCurrentTime(sqlite3_vfs*, double*); static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static sqlite3_vfs sqlite3OsKvvfsObject = { - 1, /* iVersion */ + 2, /* iVersion */ sizeof(KVVfsFile), /* szOsFile */ 1024, /* mxPathname */ 0, /* pNext */ @@ -38387,23 +39246,37 @@ static sqlite3_io_methods kvvfs_jrnl_io_methods = { /* Forward declarations for the low-level storage engine */ -static int kvstorageWrite(const char*, const char *zKey, const char *zData); -static int kvstorageDelete(const char*, const char *zKey); -static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf); -#define KVSTORAGE_KEY_SZ 32 +#ifndef SQLITE_WASM +/* In WASM builds these are implemented in JS. */ +static int kvrecordWrite(const char*, const char *zKey, const char *zData); +static int kvrecordDelete(const char*, const char *zKey); +static int kvrecordRead(const char*, const char *zKey, char *zBuf, int nBuf); +#endif +#ifndef KVRECORD_KEY_SZ +#define KVRECORD_KEY_SZ 32 +#endif /* Expand the key name with an appropriate prefix and put the result ** in zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least -** KVSTORAGE_KEY_SZ bytes. +** KVRECORD_KEY_SZ bytes. */ -static void kvstorageMakeKey( +static void kvrecordMakeKey( const char *zClass, const char *zKeyIn, char *zKeyOut ){ - sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn); + assert( zKeyIn ); + assert( zKeyOut ); + assert( zClass ); + sqlite3_snprintf(KVRECORD_KEY_SZ, zKeyOut, "kvvfs-%s-%s", + zClass, zKeyIn); } +#ifndef SQLITE_WASM +/* In WASM builds do not define APIs which use fopen(), fwrite(), +** and the like because those APIs are a portability issue for +** WASM. +*/ /* Write content into a key. zClass is the particular namespace of the ** underlying key/value store to use - either "local" or "session". ** @@ -38411,14 +39284,14 @@ static void kvstorageMakeKey( ** ** Return the number of errors. */ -static int kvstorageWrite( +static int kvrecordWrite( const char *zClass, const char *zKey, const char *zData ){ FILE *fd; - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); fd = fopen(zXKey, "wb"); if( fd ){ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey, @@ -38436,9 +39309,9 @@ static int kvstorageWrite( ** namespace given by zClass. If the key does not previously exist, ** this routine is a no-op. */ -static int kvstorageDelete(const char *zClass, const char *zKey){ - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); +static int kvrecordDelete(const char *zClass, const char *zKey){ + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); unlink(zXKey); SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey)); return 0; @@ -38459,7 +39332,7 @@ static int kvstorageDelete(const char *zClass, const char *zKey){ ** zero-terminates zBuf at zBuf[0] and returns the size of the data ** without reading it. */ -static int kvstorageRead( +static int kvrecordRead( const char *zClass, const char *zKey, char *zBuf, @@ -38467,8 +39340,8 @@ static int kvstorageRead( ){ FILE *fd; struct stat buf; - char zXKey[KVSTORAGE_KEY_SZ]; - kvstorageMakeKey(zClass, zKey, zXKey); + char zXKey[KVRECORD_KEY_SZ]; + kvrecordMakeKey(zClass, zKey, zXKey); if( access(zXKey, R_OK)!=0 || stat(zXKey, &buf)!=0 || !S_ISREG(buf.st_mode) @@ -38500,6 +39373,8 @@ static int kvstorageRead( return (int)n; } } +#endif /* #ifndef SQLITE_WASM */ + /* ** An internal level of indirection which enables us to replace the @@ -38507,17 +39382,27 @@ static int kvstorageRead( ** Maintenance reminder: if this struct changes in any way, the JSON ** rendering of its structure must be updated in ** sqlite3-wasm.c:sqlite3__wasm_enum_json(). There are no binary -** compatibility concerns, so it does not need an iVersion -** member. +** compatibility concerns, so it does not need an iVersion member. */ typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods; struct sqlite3_kvvfs_methods { - int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf); - int (*xWrite)(const char *zClass, const char *zKey, const char *zData); - int (*xDelete)(const char *zClass, const char *zKey); + int (*xRcrdRead)(const char*, const char *zKey, char *zBuf, int nBuf); + int (*xRcrdWrite)(const char*, const char *zKey, const char *zData); + int (*xRcrdDelete)(const char*, const char *zKey); const int nKeySize; + const int nBufferSize; +#ifndef SQLITE_WASM +# define MAYBE_CONST const +#else +# define MAYBE_CONST +#endif + MAYBE_CONST sqlite3_vfs * pVfs; + MAYBE_CONST sqlite3_io_methods *pIoDb; + MAYBE_CONST sqlite3_io_methods *pIoJrnl; +#undef MAYBE_CONST }; + /* ** This object holds the kvvfs I/O methods which may be swapped out ** for JavaScript-side implementations in WASM builds. In such builds @@ -38532,10 +39417,20 @@ struct sqlite3_kvvfs_methods { const #endif SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = { -kvstorageRead, -kvstorageWrite, -kvstorageDelete, -KVSTORAGE_KEY_SZ +#ifndef SQLITE_WASM + .xRcrdRead = kvrecordRead, + .xRcrdWrite = kvrecordWrite, + .xRcrdDelete = kvrecordDelete, +#else + .xRcrdRead = 0, + .xRcrdWrite = 0, + .xRcrdDelete = 0, +#endif + .nKeySize = KVRECORD_KEY_SZ, + .nBufferSize = SQLITE_KVOS_SZ, + .pVfs = &sqlite3OsKvvfsObject, + .pIoDb = &kvvfs_db_io_methods, + .pIoJrnl = &kvvfs_jrnl_io_methods }; /****** Utility subroutines ************************************************/ @@ -38562,7 +39457,10 @@ KVSTORAGE_KEY_SZ ** of hexadecimal and base-26 numbers, it is always clear where ** one stops and the next begins. */ -static int kvvfsEncode(const char *aData, int nData, char *aOut){ +#ifndef SQLITE_WASM +static +#endif +int kvvfsEncode(const char *aData, int nData, char *aOut){ int i, j; const unsigned char *a = (const unsigned char*)aData; for(i=j=0; izClass, "sz", zData, sizeof(zData)-1); + sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "sz", zData, + sizeof(zData)-1); return strtoll(zData, 0, 0); } static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){ char zData[50]; sqlite3_snprintf(sizeof(zData), zData, "%lld", sz); - return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData); + return sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "sz", zData); } /****** sqlite3_io_methods methods ******************************************/ @@ -38714,6 +39617,9 @@ static int kvvfsClose(sqlite3_file *pProtoFile){ pFile->isJournal ? "journal" : "db")); sqlite3_free(pFile->aJrnl); sqlite3_free(pFile->aData); +#ifdef SQLITE_WASM + memset(pFile, 0, sizeof(*pFile)); +#endif return SQLITE_OK; } @@ -38730,16 +39636,22 @@ static int kvvfsReadJrnl( assert( pFile->isJournal ); SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); if( pFile->aJrnl==0 ){ - int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0); + int rc; + int szTxt = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl", + 0, 0); char *aTxt; if( szTxt<=4 ){ return SQLITE_IOERR; } aTxt = sqlite3_malloc64( szTxt+1 ); if( aTxt==0 ) return SQLITE_NOMEM; - kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1); - kvvfsDecodeJournal(pFile, aTxt, szTxt); + rc = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, "jrnl", + aTxt, szTxt+1); + if( rc>=0 ){ + kvvfsDecodeJournal(pFile, aTxt, szTxt); + } sqlite3_free(aTxt); + if( rc ) return rc; if( pFile->aJrnl==0 ) return SQLITE_IOERR; } if( iOfst+iAmt>pFile->nJrnl ){ @@ -38779,8 +39691,8 @@ static int kvvfsReadDb( pgno = 1; } sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); - got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey, - aData, SQLITE_KVOS_SZ-1); + got = sqlite3KvvfsMethods.xRcrdRead(pFile->zClass, zKey, + aData, SQLITE_KVOS_SZ-1); if( got<0 ){ n = 0; }else{ @@ -38848,6 +39760,7 @@ static int kvvfsWriteDb( unsigned int pgno; char zKey[30]; char *aData = pFile->aData; + int rc; SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst)); assert( iAmt>=512 && iAmt<=65536 ); assert( (iAmt & (iAmt-1))==0 ); @@ -38856,13 +39769,13 @@ static int kvvfsWriteDb( pgno = 1 + iOfst/iAmt; sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); kvvfsEncode(zBuf, iAmt, aData); - if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){ - return SQLITE_IOERR; + rc = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, zKey, aData); + if( 0==rc ){ + if( iOfst+iAmt > pFile->szDb ){ + pFile->szDb = iOfst + iAmt; + } } - if( iOfst+iAmt > pFile->szDb ){ - pFile->szDb = iOfst + iAmt; - } - return SQLITE_OK; + return rc; } /* @@ -38872,7 +39785,7 @@ static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){ KVVfsFile *pFile = (KVVfsFile *)pProtoFile; SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size)); assert( size==0 ); - sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl"); + sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, "jrnl"); sqlite3_free(pFile->aJrnl); pFile->aJrnl = 0; pFile->nJrnl = 0; @@ -38891,7 +39804,7 @@ static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){ pgnoMax = 2 + pFile->szDb/pFile->szPage; while( pgno<=pgnoMax ){ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno); - sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey); + sqlite3KvvfsMethods.xRcrdDelete(pFile->zClass, zKey); pgno++; } pFile->szDb = size; @@ -38923,7 +39836,7 @@ static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){ }while( n>0 ); zOut[i++] = ' '; kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]); - i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut); + i = sqlite3KvvfsMethods.xRcrdWrite(pFile->zClass, "jrnl", zOut); sqlite3_free(zOut); return i ? SQLITE_IOERR : SQLITE_OK; } @@ -39037,33 +39950,32 @@ static int kvvfsOpen( KVVfsFile *pFile = (KVVfsFile*)pProtoFile; if( zName==0 ) zName = ""; SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName)); - if( strcmp(zName, "local")==0 - || strcmp(zName, "session")==0 - ){ - pFile->isJournal = 0; - pFile->base.pMethods = &kvvfs_db_io_methods; - }else - if( strcmp(zName, "local-journal")==0 - || strcmp(zName, "session-journal")==0 - ){ + assert(!pFile->zClass); + assert(!pFile->aData); + assert(!pFile->aJrnl); + assert(!pFile->nJrnl); + assert(!pFile->base.pMethods); + pFile->szPage = -1; + pFile->szDb = -1; + if( 0==sqlite3_strglob("*-journal", zName) ){ pFile->isJournal = 1; pFile->base.pMethods = &kvvfs_jrnl_io_methods; + if( 0==strcmp("session-journal",zName) ){ + pFile->zClass = "session"; + }else if( 0==strcmp("local-journal",zName) ){ + pFile->zClass = "local"; + } }else{ - return SQLITE_CANTOPEN; + pFile->isJournal = 0; + pFile->base.pMethods = &kvvfs_db_io_methods; } - if( zName[0]=='s' ){ - pFile->zClass = "session"; - }else{ - pFile->zClass = "local"; + if( !pFile->zClass ){ + pFile->zClass = zName; } pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ); if( pFile->aData==0 ){ return SQLITE_NOMEM; } - pFile->aJrnl = 0; - pFile->nJrnl = 0; - pFile->szPage = -1; - pFile->szDb = -1; return SQLITE_OK; } @@ -39073,13 +39985,17 @@ static int kvvfsOpen( ** returning. */ static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ + int rc /* The JS impl can fail with OOM in argument conversion */; if( strcmp(zPath, "local-journal")==0 ){ - sqlite3KvvfsMethods.xDelete("local", "jrnl"); + rc = sqlite3KvvfsMethods.xRcrdDelete("local", "jrnl"); }else if( strcmp(zPath, "session-journal")==0 ){ - sqlite3KvvfsMethods.xDelete("session", "jrnl"); + rc = sqlite3KvvfsMethods.xRcrdDelete("session", "jrnl"); } - return SQLITE_OK; + else{ + rc = 0; + } + return rc; } /* @@ -39093,21 +40009,42 @@ static int kvvfsAccess( int *pResOut ){ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath)); +#if 0 && defined(SQLITE_WASM) + /* + ** This is not having the desired effect in the JS bindings. + ** It's ostensibly the same logic as the #else block, but + ** it's not behaving that way. + ** + ** In JS we map all zPaths to Storage objects, and -journal files + ** are mapped to the storage for the main db (which is is exactly + ** what the mapping of "local-journal" -> "local" is doing). + */ + const char *zKey = (0==sqlite3_strglob("*-journal", zPath)) + ? "jrnl" : "sz"; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead(zPath, zKey, 0, 0)>0; +#else if( strcmp(zPath, "local-journal")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("local", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "session-journal")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("session", "jrnl", 0, 0)>0; }else if( strcmp(zPath, "local")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("local", "sz", 0, 0)>0; }else if( strcmp(zPath, "session")==0 ){ - *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0; + *pResOut = + sqlite3KvvfsMethods.xRcrdRead("session", "sz", 0, 0)>0; }else { *pResOut = 0; } + /*all current JS tests avoid triggering: assert( *pResOut == 0 ); */ +#endif SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut)); return SQLITE_OK; } @@ -44391,7 +45328,7 @@ static int unixShmMap( } /* Map the requested memory region into this processes address space. */ - apNew = (char **)sqlite3_realloc( + apNew = (char **)sqlite3_realloc64( pShmNode->apRegion, nReqRegion*sizeof(char *) ); if( !apNew ){ @@ -47836,7 +48773,7 @@ SQLITE_API int sqlite3_os_end(void){ ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(SQLITE_WIN32_NO_ANSI) +#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_ANSI) # define SQLITE_WIN32_HAS_ANSI #endif @@ -47844,7 +48781,7 @@ SQLITE_API int sqlite3_os_end(void){ ** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions ** based on the sub-platform)? */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT) && \ +#if (SQLITE_OS_WINCE || SQLITE_OS_WINNT) && \ !defined(SQLITE_WIN32_NO_WIDE) # define SQLITE_WIN32_HAS_WIDE #endif @@ -47983,16 +48920,7 @@ SQLITE_API int sqlite3_os_end(void){ */ #if SQLITE_WIN32_FILEMAPPING_API && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) -/* -** Two of the file mapping APIs are different under WinRT. Figure out which -** set we need. -*/ -#if SQLITE_OS_WINRT -WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \ - LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR); -WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T); -#else #if defined(SQLITE_WIN32_HAS_ANSI) WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \ DWORD, DWORD, DWORD, LPCSTR); @@ -48004,7 +48932,6 @@ WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \ #endif /* defined(SQLITE_WIN32_HAS_WIDE) */ WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T); -#endif /* SQLITE_OS_WINRT */ /* ** These file mapping APIs are common to both Win32 and WinRT. @@ -48295,7 +49222,7 @@ static LONG SQLITE_WIN32_VOLATILE sqlite3_os_type = 0; ** This function is not available on Windows CE or WinRT. */ -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT +#if SQLITE_OS_WINCE # define osAreFileApisANSI() 1 #endif @@ -48310,7 +49237,7 @@ static struct win_syscall { sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ sqlite3_syscall_ptr pDefault; /* Default value */ } aSyscall[] = { -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 }, #else { "AreFileApisANSI", (SYSCALL)0, 0 }, @@ -48349,7 +49276,7 @@ static struct win_syscall { #define osCreateFileA ((HANDLE(WINAPI*)(LPCSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[4].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "CreateFileW", (SYSCALL)CreateFileW, 0 }, #else { "CreateFileW", (SYSCALL)0, 0 }, @@ -48358,7 +49285,7 @@ static struct win_syscall { #define osCreateFileW ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD, \ LPSECURITY_ATTRIBUTES,DWORD,DWORD,HANDLE))aSyscall[5].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_ANSI) && \ +#if defined(SQLITE_WIN32_HAS_ANSI) && \ (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) && \ SQLITE_WIN32_CREATEFILEMAPPINGA { "CreateFileMappingA", (SYSCALL)CreateFileMappingA, 0 }, @@ -48369,8 +49296,8 @@ static struct win_syscall { #define osCreateFileMappingA ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCSTR))aSyscall[6].pCurrent) -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if (SQLITE_OS_WINCE || defined(SQLITE_WIN32_HAS_WIDE)) && \ + (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) { "CreateFileMappingW", (SYSCALL)CreateFileMappingW, 0 }, #else { "CreateFileMappingW", (SYSCALL)0, 0 }, @@ -48379,7 +49306,7 @@ static struct win_syscall { #define osCreateFileMappingW ((HANDLE(WINAPI*)(HANDLE,LPSECURITY_ATTRIBUTES, \ DWORD,DWORD,DWORD,LPCWSTR))aSyscall[7].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "CreateMutexW", (SYSCALL)CreateMutexW, 0 }, #else { "CreateMutexW", (SYSCALL)0, 0 }, @@ -48465,7 +49392,7 @@ static struct win_syscall { #define osGetDiskFreeSpaceA ((BOOL(WINAPI*)(LPCSTR,LPDWORD,LPDWORD,LPDWORD, \ LPDWORD))aSyscall[18].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "GetDiskFreeSpaceW", (SYSCALL)GetDiskFreeSpaceW, 0 }, #else { "GetDiskFreeSpaceW", (SYSCALL)0, 0 }, @@ -48482,7 +49409,7 @@ static struct win_syscall { #define osGetFileAttributesA ((DWORD(WINAPI*)(LPCSTR))aSyscall[20].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "GetFileAttributesW", (SYSCALL)GetFileAttributesW, 0 }, #else { "GetFileAttributesW", (SYSCALL)0, 0 }, @@ -48499,11 +49426,7 @@ static struct win_syscall { #define osGetFileAttributesExW ((BOOL(WINAPI*)(LPCWSTR,GET_FILEEX_INFO_LEVELS, \ LPVOID))aSyscall[22].pCurrent) -#if !SQLITE_OS_WINRT { "GetFileSize", (SYSCALL)GetFileSize, 0 }, -#else - { "GetFileSize", (SYSCALL)0, 0 }, -#endif #define osGetFileSize ((DWORD(WINAPI*)(HANDLE,LPDWORD))aSyscall[23].pCurrent) @@ -48516,7 +49439,7 @@ static struct win_syscall { #define osGetFullPathNameA ((DWORD(WINAPI*)(LPCSTR,DWORD,LPSTR, \ LPSTR*))aSyscall[24].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if !SQLITE_OS_WINCE && defined(SQLITE_WIN32_HAS_WIDE) { "GetFullPathNameW", (SYSCALL)GetFullPathNameW, 0 }, #else { "GetFullPathNameW", (SYSCALL)0, 0 }, @@ -48551,16 +49474,10 @@ static struct win_syscall { #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \ LPCSTR))aSyscall[27].pCurrent) -#if !SQLITE_OS_WINRT { "GetSystemInfo", (SYSCALL)GetSystemInfo, 0 }, -#else - { "GetSystemInfo", (SYSCALL)0, 0 }, -#endif - #define osGetSystemInfo ((VOID(WINAPI*)(LPSYSTEM_INFO))aSyscall[28].pCurrent) { "GetSystemTime", (SYSCALL)GetSystemTime, 0 }, - #define osGetSystemTime ((VOID(WINAPI*)(LPSYSTEMTIME))aSyscall[29].pCurrent) #if !SQLITE_OS_WINCE @@ -48580,7 +49497,7 @@ static struct win_syscall { #define osGetTempPathA ((DWORD(WINAPI*)(DWORD,LPSTR))aSyscall[31].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) { "GetTempPathW", (SYSCALL)GetTempPathW, 0 }, #else { "GetTempPathW", (SYSCALL)0, 0 }, @@ -48588,11 +49505,7 @@ static struct win_syscall { #define osGetTempPathW ((DWORD(WINAPI*)(DWORD,LPWSTR))aSyscall[32].pCurrent) -#if !SQLITE_OS_WINRT { "GetTickCount", (SYSCALL)GetTickCount, 0 }, -#else - { "GetTickCount", (SYSCALL)0, 0 }, -#endif #define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent) @@ -48605,7 +49518,7 @@ static struct win_syscall { #define osGetVersionExA ((BOOL(WINAPI*)( \ LPOSVERSIONINFOA))aSyscall[34].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ +#if defined(SQLITE_WIN32_HAS_WIDE) && \ SQLITE_WIN32_GETVERSIONEX { "GetVersionExW", (SYSCALL)GetVersionExW, 0 }, #else @@ -48620,20 +49533,12 @@ static struct win_syscall { #define osHeapAlloc ((LPVOID(WINAPI*)(HANDLE,DWORD, \ SIZE_T))aSyscall[36].pCurrent) -#if !SQLITE_OS_WINRT { "HeapCreate", (SYSCALL)HeapCreate, 0 }, -#else - { "HeapCreate", (SYSCALL)0, 0 }, -#endif #define osHeapCreate ((HANDLE(WINAPI*)(DWORD,SIZE_T, \ SIZE_T))aSyscall[37].pCurrent) -#if !SQLITE_OS_WINRT { "HeapDestroy", (SYSCALL)HeapDestroy, 0 }, -#else - { "HeapDestroy", (SYSCALL)0, 0 }, -#endif #define osHeapDestroy ((BOOL(WINAPI*)(HANDLE))aSyscall[38].pCurrent) @@ -48651,16 +49556,12 @@ static struct win_syscall { #define osHeapSize ((SIZE_T(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[41].pCurrent) -#if !SQLITE_OS_WINRT { "HeapValidate", (SYSCALL)HeapValidate, 0 }, -#else - { "HeapValidate", (SYSCALL)0, 0 }, -#endif #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \ LPCVOID))aSyscall[42].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "HeapCompact", (SYSCALL)HeapCompact, 0 }, #else { "HeapCompact", (SYSCALL)0, 0 }, @@ -48676,7 +49577,7 @@ static struct win_syscall { #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[44].pCurrent) -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \ +#if defined(SQLITE_WIN32_HAS_WIDE) && \ !defined(SQLITE_OMIT_LOAD_EXTENSION) { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 }, #else @@ -48685,15 +49586,11 @@ static struct win_syscall { #define osLoadLibraryW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[45].pCurrent) -#if !SQLITE_OS_WINRT { "LocalFree", (SYSCALL)LocalFree, 0 }, -#else - { "LocalFree", (SYSCALL)0, 0 }, -#endif #define osLocalFree ((HLOCAL(WINAPI*)(HLOCAL))aSyscall[46].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "LockFile", (SYSCALL)LockFile, 0 }, #else { "LockFile", (SYSCALL)0, 0 }, @@ -48715,8 +49612,7 @@ static struct win_syscall { LPOVERLAPPED))aSyscall[48].pCurrent) #endif -#if SQLITE_OS_WINCE || (!SQLITE_OS_WINRT && \ - (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)) +#if SQLITE_OS_WINCE || !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "MapViewOfFile", (SYSCALL)MapViewOfFile, 0 }, #else { "MapViewOfFile", (SYSCALL)0, 0 }, @@ -48744,20 +49640,12 @@ static struct win_syscall { #define osSetEndOfFile ((BOOL(WINAPI*)(HANDLE))aSyscall[53].pCurrent) -#if !SQLITE_OS_WINRT { "SetFilePointer", (SYSCALL)SetFilePointer, 0 }, -#else - { "SetFilePointer", (SYSCALL)0, 0 }, -#endif #define osSetFilePointer ((DWORD(WINAPI*)(HANDLE,LONG,PLONG, \ DWORD))aSyscall[54].pCurrent) -#if !SQLITE_OS_WINRT { "Sleep", (SYSCALL)Sleep, 0 }, -#else - { "Sleep", (SYSCALL)0, 0 }, -#endif #define osSleep ((VOID(WINAPI*)(DWORD))aSyscall[55].pCurrent) @@ -48766,7 +49654,7 @@ static struct win_syscall { #define osSystemTimeToFileTime ((BOOL(WINAPI*)(const SYSTEMTIME*, \ LPFILETIME))aSyscall[56].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE { "UnlockFile", (SYSCALL)UnlockFile, 0 }, #else { "UnlockFile", (SYSCALL)0, 0 }, @@ -48804,15 +49692,6 @@ static struct win_syscall { #define osWriteFile ((BOOL(WINAPI*)(HANDLE,LPCVOID,DWORD,LPDWORD, \ LPOVERLAPPED))aSyscall[61].pCurrent) -#if SQLITE_OS_WINRT - { "CreateEventExW", (SYSCALL)CreateEventExW, 0 }, -#else - { "CreateEventExW", (SYSCALL)0, 0 }, -#endif - -#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \ - DWORD,DWORD))aSyscall[62].pCurrent) - /* ** For WaitForSingleObject(), MSDN says: ** @@ -48822,7 +49701,7 @@ static struct win_syscall { { "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 }, #define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \ - DWORD))aSyscall[63].pCurrent) + DWORD))aSyscall[62].pCurrent) #if !SQLITE_OS_WINCE { "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 }, @@ -48831,69 +49710,12 @@ static struct win_syscall { #endif #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ - BOOL))aSyscall[64].pCurrent) + BOOL))aSyscall[63].pCurrent) -#if SQLITE_OS_WINRT - { "SetFilePointerEx", (SYSCALL)SetFilePointerEx, 0 }, -#else - { "SetFilePointerEx", (SYSCALL)0, 0 }, -#endif - -#define osSetFilePointerEx ((BOOL(WINAPI*)(HANDLE,LARGE_INTEGER, \ - PLARGE_INTEGER,DWORD))aSyscall[65].pCurrent) - -#if SQLITE_OS_WINRT - { "GetFileInformationByHandleEx", (SYSCALL)GetFileInformationByHandleEx, 0 }, -#else - { "GetFileInformationByHandleEx", (SYSCALL)0, 0 }, -#endif - -#define osGetFileInformationByHandleEx ((BOOL(WINAPI*)(HANDLE, \ - FILE_INFO_BY_HANDLE_CLASS,LPVOID,DWORD))aSyscall[66].pCurrent) - -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) - { "MapViewOfFileFromApp", (SYSCALL)MapViewOfFileFromApp, 0 }, -#else - { "MapViewOfFileFromApp", (SYSCALL)0, 0 }, -#endif - -#define osMapViewOfFileFromApp ((LPVOID(WINAPI*)(HANDLE,ULONG,ULONG64, \ - SIZE_T))aSyscall[67].pCurrent) - -#if SQLITE_OS_WINRT - { "CreateFile2", (SYSCALL)CreateFile2, 0 }, -#else - { "CreateFile2", (SYSCALL)0, 0 }, -#endif - -#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \ - LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[68].pCurrent) - -#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION) - { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 }, -#else - { "LoadPackagedLibrary", (SYSCALL)0, 0 }, -#endif - -#define osLoadPackagedLibrary ((HMODULE(WINAPI*)(LPCWSTR, \ - DWORD))aSyscall[69].pCurrent) - -#if SQLITE_OS_WINRT - { "GetTickCount64", (SYSCALL)GetTickCount64, 0 }, -#else - { "GetTickCount64", (SYSCALL)0, 0 }, -#endif - -#define osGetTickCount64 ((ULONGLONG(WINAPI*)(VOID))aSyscall[70].pCurrent) - -#if SQLITE_OS_WINRT { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, -#else - { "GetNativeSystemInfo", (SYSCALL)0, 0 }, -#endif #define osGetNativeSystemInfo ((VOID(WINAPI*)( \ - LPSYSTEM_INFO))aSyscall[71].pCurrent) + LPSYSTEM_INFO))aSyscall[64].pCurrent) #if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, @@ -48901,7 +49723,7 @@ static struct win_syscall { { "OutputDebugStringA", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[72].pCurrent) +#define osOutputDebugStringA ((VOID(WINAPI*)(LPCSTR))aSyscall[65].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) { "OutputDebugStringW", (SYSCALL)OutputDebugStringW, 0 }, @@ -48909,20 +49731,11 @@ static struct win_syscall { { "OutputDebugStringW", (SYSCALL)0, 0 }, #endif -#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[73].pCurrent) +#define osOutputDebugStringW ((VOID(WINAPI*)(LPCWSTR))aSyscall[66].pCurrent) { "GetProcessHeap", (SYSCALL)GetProcessHeap, 0 }, -#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[74].pCurrent) - -#if SQLITE_OS_WINRT && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) - { "CreateFileMappingFromApp", (SYSCALL)CreateFileMappingFromApp, 0 }, -#else - { "CreateFileMappingFromApp", (SYSCALL)0, 0 }, -#endif - -#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ - LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) +#define osGetProcessHeap ((HANDLE(WINAPI*)(VOID))aSyscall[67].pCurrent) /* ** NOTE: On some sub-platforms, the InterlockedCompareExchange "function" @@ -48937,25 +49750,25 @@ static struct win_syscall { { "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 }, #define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \ - SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent) + SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[68].pCurrent) #endif /* defined(InterlockedCompareExchange) */ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { "UuidCreate", (SYSCALL)UuidCreate, 0 }, #else { "UuidCreate", (SYSCALL)0, 0 }, #endif -#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[77].pCurrent) +#define osUuidCreate ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[69].pCurrent) -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { "UuidCreateSequential", (SYSCALL)UuidCreateSequential, 0 }, #else { "UuidCreateSequential", (SYSCALL)0, 0 }, #endif #define osUuidCreateSequential \ - ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[78].pCurrent) + ((RPC_STATUS(RPC_ENTRY*)(UUID*))aSyscall[70].pCurrent) #if !defined(SQLITE_NO_SYNC) && SQLITE_MAX_MMAP_SIZE>0 { "FlushViewOfFile", (SYSCALL)FlushViewOfFile, 0 }, @@ -48964,7 +49777,7 @@ static struct win_syscall { #endif #define osFlushViewOfFile \ - ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent) + ((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[71].pCurrent) /* ** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent() @@ -48981,7 +49794,7 @@ static struct win_syscall { #define osCreateEvent ( \ (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \ - aSyscall[80].pCurrent \ + aSyscall[72].pCurrent \ ) /* @@ -48998,7 +49811,7 @@ static struct win_syscall { { "CancelIo", (SYSCALL)0, 0 }, #endif -#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent) +#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[73].pCurrent) #if defined(SQLITE_WIN32_HAS_WIDE) && defined(_WIN32) { "GetModuleHandleW", (SYSCALL)GetModuleHandleW, 0 }, @@ -49006,7 +49819,7 @@ static struct win_syscall { { "GetModuleHandleW", (SYSCALL)0, 0 }, #endif -#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[82].pCurrent) +#define osGetModuleHandleW ((HMODULE(WINAPI*)(LPCWSTR))aSyscall[74].pCurrent) #ifndef _WIN32 { "getenv", (SYSCALL)getenv, 0 }, @@ -49014,7 +49827,7 @@ static struct win_syscall { { "getenv", (SYSCALL)0, 0 }, #endif -#define osGetenv ((const char *(*)(const char *))aSyscall[83].pCurrent) +#define osGetenv ((const char *(*)(const char *))aSyscall[75].pCurrent) #ifndef _WIN32 { "getcwd", (SYSCALL)getcwd, 0 }, @@ -49022,7 +49835,7 @@ static struct win_syscall { { "getcwd", (SYSCALL)0, 0 }, #endif -#define osGetcwd ((char*(*)(char*,size_t))aSyscall[84].pCurrent) +#define osGetcwd ((char*(*)(char*,size_t))aSyscall[76].pCurrent) #ifndef _WIN32 { "readlink", (SYSCALL)readlink, 0 }, @@ -49030,7 +49843,7 @@ static struct win_syscall { { "readlink", (SYSCALL)0, 0 }, #endif -#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[85].pCurrent) +#define osReadlink ((ssize_t(*)(const char*,char*,size_t))aSyscall[77].pCurrent) #ifndef _WIN32 { "lstat", (SYSCALL)lstat, 0 }, @@ -49038,7 +49851,7 @@ static struct win_syscall { { "lstat", (SYSCALL)0, 0 }, #endif -#define osLstat ((int(*)(const char*,struct stat*))aSyscall[86].pCurrent) +#define osLstat ((int(*)(const char*,struct stat*))aSyscall[78].pCurrent) #ifndef _WIN32 { "__errno", (SYSCALL)__errno, 0 }, @@ -49046,7 +49859,7 @@ static struct win_syscall { { "__errno", (SYSCALL)0, 0 }, #endif -#define osErrno (*((int*(*)(void))aSyscall[87].pCurrent)()) +#define osErrno (*((int*(*)(void))aSyscall[79].pCurrent)()) #ifndef _WIN32 { "cygwin_conv_path", (SYSCALL)cygwin_conv_path, 0 }, @@ -49055,7 +49868,7 @@ static struct win_syscall { #endif #define osCygwin_conv_path ((size_t(*)(unsigned int, \ - const void *, void *, size_t))aSyscall[88].pCurrent) + const void *, void *, size_t))aSyscall[80].pCurrent) }; /* End of the overrideable system calls */ @@ -49159,10 +49972,10 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){ DWORD lastErrno = osGetLastError(); if( lastErrno==NO_ERROR ){ @@ -49275,28 +50088,11 @@ SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ } #endif /* _WIN32 */ -/* -** The following routine suspends the current thread for at least ms -** milliseconds. This is equivalent to the Win32 Sleep() interface. -*/ -#if SQLITE_OS_WINRT -static HANDLE sleepObj = NULL; -#endif - SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){ -#if SQLITE_OS_WINRT - if ( sleepObj==NULL ){ - sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET, - SYNCHRONIZE); - } - assert( sleepObj!=NULL ); - osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE); -#else osSleep(milliseconds); -#endif } -#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ +#if SQLITE_MAX_WORKER_THREADS>0 && !SQLITE_OS_WINCE && \ SQLITE_THREADSAFE>0 SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ DWORD rc; @@ -49320,7 +50116,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ #if !SQLITE_WIN32_GETVERSIONEX # define osIsNT() (1) -#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI) +#elif SQLITE_OS_WINCE || !defined(SQLITE_WIN32_HAS_ANSI) # define osIsNT() (1) #elif !defined(SQLITE_WIN32_HAS_WIDE) # define osIsNT() (0) @@ -49333,13 +50129,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){ ** based on the NT kernel. */ SQLITE_API int sqlite3_win32_is_nt(void){ -#if SQLITE_OS_WINRT - /* - ** NOTE: The WinRT sub-platform is always assumed to be based on the NT - ** kernel. - */ - return 1; -#elif SQLITE_WIN32_GETVERSIONEX +#if SQLITE_WIN32_GETVERSIONEX if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){ #if defined(SQLITE_WIN32_HAS_ANSI) OSVERSIONINFOA sInfo; @@ -49381,7 +50171,7 @@ static void *winMemMalloc(int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif assert( nBytes>=0 ); @@ -49403,7 +50193,7 @@ static void winMemFree(void *pPrior){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */ @@ -49424,7 +50214,7 @@ static void *winMemRealloc(void *pPrior, int nBytes){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ); #endif assert( nBytes>=0 ); @@ -49452,7 +50242,7 @@ static int winMemSize(void *p){ hHeap = winMemGetHeap(); assert( hHeap!=0 ); assert( hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, p) ); #endif if( !p ) return 0; @@ -49482,7 +50272,7 @@ static int winMemInit(void *pAppData){ assert( pWinMemData->magic1==WINMEM_MAGIC1 ); assert( pWinMemData->magic2==WINMEM_MAGIC2 ); -#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE +#if SQLITE_WIN32_HEAP_CREATE if( !pWinMemData->hHeap ){ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE; DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap; @@ -49515,7 +50305,7 @@ static int winMemInit(void *pAppData){ #endif assert( pWinMemData->hHeap!=0 ); assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif return SQLITE_OK; @@ -49533,7 +50323,7 @@ static void winMemShutdown(void *pAppData){ if( pWinMemData->hHeap ){ assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE ); -#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE) +#if defined(SQLITE_WIN32_MALLOC_VALIDATE) assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) ); #endif if( pWinMemData->bOwned ){ @@ -49914,17 +50704,6 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ char *zOut = 0; if( osIsNT() ){ -#if SQLITE_OS_WINRT - WCHAR zTempWide[SQLITE_WIN32_MAX_ERRMSG_CHARS+1]; - dwLen = osFormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - lastErrno, - 0, - zTempWide, - SQLITE_WIN32_MAX_ERRMSG_CHARS, - 0); -#else LPWSTR zTempWide = NULL; dwLen = osFormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | @@ -49935,16 +50714,13 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ (LPWSTR) &zTempWide, 0, 0); -#endif if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ sqlite3BeginBenignMalloc(); zOut = winUnicodeToUtf8(zTempWide); sqlite3EndBenignMalloc(); -#if !SQLITE_OS_WINRT /* free the system buffer allocated by FormatMessage */ osLocalFree(zTempWide); -#endif } } #ifdef SQLITE_WIN32_HAS_ANSI @@ -50605,7 +51381,6 @@ static int winHandleUnlock(HANDLE h, int iOff, int nByte){ static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ int rc = SQLITE_OK; /* Return value */ -#if !SQLITE_OS_WINRT LONG upperBits; /* Most sig. 32 bits of new offset */ LONG lowerBits; /* Least sig. 32 bits of new offset */ DWORD dwRet; /* Value returned by SetFilePointer() */ @@ -50627,20 +51402,7 @@ static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){ rc = SQLITE_IOERR_SEEK; } } -#else - /* This implementation works for WinRT. */ - LARGE_INTEGER x; /* The new offset */ - BOOL bRet; /* Value returned by SetFilePointerEx() */ - - x.QuadPart = iOffset; - bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN); - - if(!bRet){ - rc = SQLITE_IOERR_SEEK; - } -#endif - - OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc))); + OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset,sqlite3ErrName(rc))); return rc; } @@ -50941,17 +51703,6 @@ static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){ */ static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ int rc = SQLITE_OK; - -#if SQLITE_OS_WINRT - FILE_STANDARD_INFO info; - BOOL b; - b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info)); - if( b ){ - *pnByte = info.EndOfFile.QuadPart; - }else{ - rc = SQLITE_IOERR_FSTAT; - } -#else DWORD upperBits = 0; DWORD lowerBits = 0; @@ -50961,8 +51712,6 @@ static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){ if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){ rc = SQLITE_IOERR_FSTAT; } -#endif - return rc; } @@ -51161,20 +51910,6 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ assert( pSize!=0 ); SimulateIOError(return SQLITE_IOERR_FSTAT); OSTRACE(("SIZE file=%p, pSize=%p\n", pFile->h, pSize)); - -#if SQLITE_OS_WINRT - { - FILE_STANDARD_INFO info; - if( osGetFileInformationByHandleEx(pFile->h, FileStandardInfo, - &info, sizeof(info)) ){ - *pSize = info.EndOfFile.QuadPart; - }else{ - pFile->lastErrno = osGetLastError(); - rc = winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, - "winFileSize", pFile->zPath); - } - } -#else { DWORD upperBits; DWORD lowerBits; @@ -51189,7 +51924,6 @@ static int winFileSize(sqlite3_file *id, sqlite3_int64 *pSize){ "winFileSize", pFile->zPath); } } -#endif OSTRACE(("SIZE file=%p, pSize=%p, *pSize=%lld, rc=%s\n", pFile->h, pSize, *pSize, sqlite3ErrName(rc))); return rc; @@ -52151,20 +52885,6 @@ static int winHandleOpen( ** TODO: retry-on-ioerr. */ if( osIsNT() ){ -#if SQLITE_OS_WINRT - CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; - memset(&extendedParameters, 0, sizeof(extendedParameters)); - extendedParameters.dwSize = sizeof(extendedParameters); - extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; - extendedParameters.dwFileFlags = flag_overlapped; - extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; - h = osCreateFile2((LPCWSTR)zConverted, - (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */ - FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ - OPEN_ALWAYS, /* dwCreationDisposition */ - &extendedParameters - ); -#else h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */ (GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */ @@ -52173,7 +52893,6 @@ static int winHandleOpen( FILE_ATTRIBUTE_NORMAL|flag_overlapped, NULL ); -#endif }else{ /* Due to pre-processor directives earlier in this file, ** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */ @@ -52641,9 +53360,7 @@ static int winShmMap( HANDLE hMap = NULL; /* file-mapping handle */ void *pMap = 0; /* Mapped memory region */ -#if SQLITE_OS_WINRT - hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL); -#elif defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL); #elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL); @@ -52655,15 +53372,9 @@ static int winShmMap( if( hMap ){ int iOffset = pShmNode->nRegion*szRegion; int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity; -#if SQLITE_OS_WINRT - pMap = osMapViewOfFileFromApp(hMap, flags, - iOffset - iOffsetShift, szRegion + iOffsetShift - ); -#else pMap = osMapViewOfFile(hMap, flags, 0, iOffset - iOffsetShift, szRegion + iOffsetShift ); -#endif OSTRACE(("SHM-MAP-MAP pid=%lu, region=%d, offset=%d, size=%d, rc=%s\n", osGetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); @@ -52796,9 +53507,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ flags |= FILE_MAP_WRITE; } #endif -#if SQLITE_OS_WINRT - pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL); -#elif defined(SQLITE_WIN32_HAS_WIDE) +#if defined(SQLITE_WIN32_HAS_WIDE) pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect, (DWORD)((nMap>>32) & 0xffffffff), (DWORD)(nMap & 0xffffffff), NULL); @@ -52818,11 +53527,7 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){ } assert( (nMap % winSysInfo.dwPageSize)==0 ); assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff ); -#if SQLITE_OS_WINRT - pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap); -#else pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap); -#endif if( pNew==NULL ){ osCloseHandle(pFd->hMap); pFd->hMap = NULL; @@ -53157,7 +53862,6 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } #endif -#if !SQLITE_OS_WINRT && defined(_WIN32) else if( osIsNT() ){ char *zMulti; LPWSTR zWidePath = sqlite3MallocZero( nMax*sizeof(WCHAR) ); @@ -53211,7 +53915,6 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ } } #endif /* SQLITE_WIN32_HAS_ANSI */ -#endif /* !SQLITE_OS_WINRT */ /* ** Check to make sure the temporary directory ends with an appropriate @@ -53386,13 +54089,6 @@ static int winOpen( memset(pFile, 0, sizeof(winFile)); pFile->h = INVALID_HANDLE_VALUE; -#if SQLITE_OS_WINRT - if( !zUtf8Name && !sqlite3_temp_directory ){ - sqlite3_log(SQLITE_ERROR, - "sqlite3_temp_directory variable should be set for WinRT"); - } -#endif - /* If the second argument to this function is NULL, generate a ** temporary file name to use */ @@ -53475,31 +54171,6 @@ static int winOpen( #endif if( osIsNT() ){ -#if SQLITE_OS_WINRT - CREATEFILE2_EXTENDED_PARAMETERS extendedParameters; - extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); - extendedParameters.dwFileAttributes = - dwFlagsAndAttributes & FILE_ATTRIBUTE_MASK; - extendedParameters.dwFileFlags = dwFlagsAndAttributes & FILE_FLAG_MASK; - extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS; - extendedParameters.lpSecurityAttributes = NULL; - extendedParameters.hTemplateFile = NULL; - do{ - h = osCreateFile2((LPCWSTR)zConverted, - dwDesiredAccess, - dwShareMode, - dwCreationDisposition, - &extendedParameters); - if( h!=INVALID_HANDLE_VALUE ) break; - if( isReadWrite ){ - int rc2; - sqlite3BeginBenignMalloc(); - rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ|NORETRY, &isRO); - sqlite3EndBenignMalloc(); - if( rc2==SQLITE_OK && isRO ) break; - } - }while( winRetryIoerr(&cnt, &lastErrno) ); -#else do{ h = osCreateFileW((LPCWSTR)zConverted, dwDesiredAccess, @@ -53516,7 +54187,6 @@ static int winOpen( if( rc2==SQLITE_OK && isRO ) break; } }while( winRetryIoerr(&cnt, &lastErrno) ); -#endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ @@ -53653,25 +54323,7 @@ static int winDelete( } if( osIsNT() ){ do { -#if SQLITE_OS_WINRT - WIN32_FILE_ATTRIBUTE_DATA sAttrData; - memset(&sAttrData, 0, sizeof(sAttrData)); - if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, - &sAttrData) ){ - attr = sAttrData.dwFileAttributes; - }else{ - lastErrno = osGetLastError(); - if( lastErrno==ERROR_FILE_NOT_FOUND - || lastErrno==ERROR_PATH_NOT_FOUND ){ - rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ - }else{ - rc = SQLITE_ERROR; - } - break; - } -#else attr = osGetFileAttributesW(zConverted); -#endif if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND @@ -53794,6 +54446,7 @@ static int winAccess( attr = sAttrData.dwFileAttributes; } }else{ + if( noRetry ) lastErrno = osGetLastError(); winLogIoerr(cnt, __LINE__); if( lastErrno!=ERROR_FILE_NOT_FOUND && lastErrno!=ERROR_PATH_NOT_FOUND ){ sqlite3_free(zConverted); @@ -53962,7 +54615,7 @@ static int winFullPathnameNoMutex( int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE int nByte; void *zConverted; char *zOut; @@ -54051,7 +54704,7 @@ static int winFullPathnameNoMutex( } #endif /* __CYGWIN__ */ -#if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && defined(_WIN32) +#if SQLITE_OS_WINCE && defined(_WIN32) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ /* WinRT has no way to convert a relative path to an absolute one. */ @@ -54070,7 +54723,7 @@ static int winFullPathnameNoMutex( return SQLITE_OK; #endif -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT +#if !SQLITE_OS_WINCE #if defined(_WIN32) /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this @@ -54202,11 +54855,7 @@ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ return 0; } if( osIsNT() ){ -#if SQLITE_OS_WINRT - h = osLoadPackagedLibrary((LPCWSTR)zConverted, 0); -#else h = osLoadLibraryW((LPCWSTR)zConverted); -#endif } #ifdef SQLITE_WIN32_HAS_ANSI else{ @@ -54288,23 +54937,16 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ DWORD pid = osGetCurrentProcessId(); xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD)); } -#if SQLITE_OS_WINRT - { - ULONGLONG cnt = osGetTickCount64(); - xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG)); - } -#else { DWORD cnt = osGetTickCount(); xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD)); } -#endif /* SQLITE_OS_WINRT */ { LARGE_INTEGER i; osQueryPerformanceCounter(&i); xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER)); } -#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID +#if !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID { UUID id; memset(&id, 0, sizeof(UUID)); @@ -54314,7 +54956,7 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ osUuidCreateSequential(&id); xorMemory(&e, (unsigned char*)&id, sizeof(UUID)); } -#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */ +#endif /* !SQLITE_OS_WINCE && SQLITE_WIN32_USE_UUID */ return e.nXor>nBuf ? nBuf : e.nXor; #endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */ } @@ -54545,15 +55187,16 @@ SQLITE_API int sqlite3_os_init(void){ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ - assert( ArraySize(aSyscall)==89 ); + assert( ArraySize(aSyscall)==81 ); + assert( strcmp(aSyscall[0].zName,"AreFileApisANSI")==0 ); + assert( strcmp(aSyscall[20].zName,"GetFileAttributesA")==0 ); + assert( strcmp(aSyscall[40].zName,"HeapReAlloc")==0 ); + assert( strcmp(aSyscall[60].zName,"WideCharToMultiByte")==0 ); + assert( strcmp(aSyscall[80].zName,"cygwin_conv_path")==0 ); /* get memory map allocation granularity */ memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); -#if SQLITE_OS_WINRT - osGetNativeSystemInfo(&winSysInfo); -#else osGetSystemInfo(&winSysInfo); -#endif assert( winSysInfo.dwAllocationGranularity>0 ); assert( winSysInfo.dwPageSize>0 ); @@ -54577,17 +55220,9 @@ SQLITE_API int sqlite3_os_init(void){ } SQLITE_API int sqlite3_os_end(void){ -#if SQLITE_OS_WINRT - if( sleepObj!=NULL ){ - osCloseHandle(sleepObj); - sleepObj = NULL; - } -#endif - #ifndef SQLITE_OMIT_WAL winBigLock = 0; #endif - return SQLITE_OK; } @@ -59736,6 +60371,8 @@ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); if( iRead ) return 0; /* Case (4) */ } +#else + UNUSED_PARAMETER(pgno); #endif assert( pPager->fd->pMethods->xDeviceCharacteristics!=0 ); if( (pPager->fd->pMethods->xDeviceCharacteristics(pPager->fd) @@ -60156,17 +60793,17 @@ static int jrnlBufferSize(Pager *pPager){ */ #ifdef SQLITE_CHECK_PAGES /* -** Return a 32-bit hash of the page data for pPage. +** Return a 64-bit hash of the page data for pPage. */ -static u32 pager_datahash(int nByte, unsigned char *pData){ - u32 hash = 0; +static u64 pager_datahash(int nByte, unsigned char *pData){ + u64 hash = 0; int i; for(i=0; ipPager->pageSize, (unsigned char *)pPage->pData); } static void pager_set_pagehash(PgHdr *pPage){ @@ -63115,6 +63752,8 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); pPager->pWal = 0; } +#else + UNUSED_PARAMETER(db); #endif pager_reset(pPager); if( MEMDB ){ @@ -67882,7 +68521,7 @@ static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){ /* ** Compute a hash on a page number. The resulting hash value must land -** between 0 and (HASHTABLE_NSLOT-1). The walHashNext() function advances +** between 0 and (HASHTABLE_NSLOT-1). The walNextHash() function advances ** the hash to the next value in the event of a collision. */ static int walHash(u32 iPage){ @@ -68090,7 +68729,7 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; } - sLoc.aPgno[idx-1] = iPage; + sLoc.aPgno[(idx-1)&(HASHTABLE_NPAGE-1)] = iPage; AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); #ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT @@ -69010,68 +69649,82 @@ static int walCheckpoint( && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK ){ u32 nBackfill = pInfo->nBackfill; - pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; + WalIndexHdr *pLive = (WalIndexHdr*)walIndexHdr(pWal); - /* Sync the WAL to disk */ - rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); + /* Now that read-lock slot 0 is locked, check that the wal has not been + ** wrapped since the header was read for this checkpoint. If it was, then + ** there was no work to do anyway. In this case the + ** (pInfo->nBackfillhdr.mxFrame) test above only passed because + ** pInfo->nBackfill had already been set to 0 by the writer that wrapped + ** the wal file. It would also be dangerous to proceed, as there may be + ** fewer than pWal->hdr.mxFrame valid frames in the wal file. */ + int bChg = memcmp(pLive->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)); + if( 0==bChg ){ + pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT; - /* If the database may grow as a result of this checkpoint, hint - ** about the eventual size of the db file to the VFS layer. - */ - if( rc==SQLITE_OK ){ - i64 nReq = ((i64)mxPage * szPage); - i64 nSize; /* Current size of database file */ - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); - rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); - if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); - } - } + /* Sync the WAL to disk */ + rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags)); - } - - /* Iterate through the contents of the WAL, copying data to the db file */ - while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ - i64 iOffset; - assert( walFramePgno(pWal, iFrame)==iDbpage ); - SEH_INJECT_FAULT; - if( AtomicLoad(&db->u1.isInterrupted) ){ - rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; - break; - } - if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ - continue; - } - iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; - /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ - rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - iOffset = (iDbpage-1)*(i64)szPage; - testcase( IS_BIG_INT(iOffset) ); - rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); - if( rc!=SQLITE_OK ) break; - } - sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); - - /* If work was actually accomplished... */ - if( rc==SQLITE_OK ){ - if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ - i64 szDb = pWal->hdr.nPage*(i64)szPage; - testcase( IS_BIG_INT(szDb) ); - rc = sqlite3OsTruncate(pWal->pDbFd, szDb); - if( rc==SQLITE_OK ){ - rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); - } - } + /* If the database may grow as a result of this checkpoint, hint + ** about the eventual size of the db file to the VFS layer. + */ if( rc==SQLITE_OK ){ - AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + i64 nReq = ((i64)mxPage * szPage); + i64 nSize; /* Current size of database file */ + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0); + rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); + if( rc==SQLITE_OK && nSizehdr.mxFrame*szPage)pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); + } + } + + } + + /* Iterate through the contents of the WAL, copying data to the + ** db file */ + while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ + i64 iOffset; + assert( walFramePgno(pWal, iFrame)==iDbpage ); + SEH_INJECT_FAULT; + if( AtomicLoad(&db->u1.isInterrupted) ){ + rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; + break; + } + if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){ + continue; + } + iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE; + /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */ + rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + iOffset = (iDbpage-1)*(i64)szPage; + testcase( IS_BIG_INT(iOffset) ); + rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); + if( rc!=SQLITE_OK ) break; + } + sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0); + + /* If work was actually accomplished... */ + if( rc==SQLITE_OK ){ + if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){ + i64 szDb = pWal->hdr.nPage*(i64)szPage; + testcase( IS_BIG_INT(szDb) ); + rc = sqlite3OsTruncate(pWal->pDbFd, szDb); + if( rc==SQLITE_OK ){ + rc = sqlite3OsSync(pWal->pDbFd, CKPT_SYNC_FLAGS(sync_flags)); + } + } + if( rc==SQLITE_OK ){ + AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT; + } } } @@ -70324,7 +70977,10 @@ static int walFindFrame( SEH_INJECT_FAULT; while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){ u32 iFrame = iH + sLoc.iZero; - if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){ + if( iFrame<=iLast + && iFrame>=pWal->minFrame + && sLoc.aPgno[(iH-1)&(HASHTABLE_NPAGE-1)]==pgno + ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } @@ -71121,6 +71777,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ + sqlite3FaultSim(660); if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ rc = SQLITE_CORRUPT_BKPT; }else if( eMode2!=SQLITE_CHECKPOINT_NOOP ){ @@ -73698,7 +74355,7 @@ static void btreeParseCellPtr( CellInfo *pInfo /* Fill in this structure */ ){ u8 *pIter; /* For scanning through pCell */ - u32 nPayload; /* Number of bytes of cell payload */ + u64 nPayload; /* Number of bytes of cell payload */ u64 iKey; /* Extracted Key value */ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); @@ -73720,6 +74377,7 @@ static void btreeParseCellPtr( do{ nPayload = (nPayload<<7) | (*++pIter & 0x7f); }while( (*pIter)>=0x80 && pIternKey = *(i64*)&iKey; - pInfo->nPayload = nPayload; + pInfo->nPayload = (u32)nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==(u32)pPage->maxLocal+1 ); - assert( nPayload>=0 ); assert( pPage->maxLocal <= BT_MAX_LOCAL ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits @@ -76109,6 +76766,30 @@ static SQLITE_NOINLINE int btreeBeginTrans( } #endif +#ifdef SQLITE_EXPERIMENTAL_PRAGMA_20251114 + /* If both a read and write transaction will be opened by this call, + ** then issue a file-control as if the following pragma command had + ** been evaluated: + ** + ** PRAGMA experimental_pragma_20251114 = 1|2 + ** + ** where the RHS is "1" if wrflag is 1 (RESERVED lock), or "2" if wrflag + ** is 2 (EXCLUSIVE lock). Ignore any result or error returned by the VFS. + ** + ** WARNING: This code will likely remain part of SQLite only temporarily - + ** it exists to allow users to experiment with certain types of blocking + ** locks in custom VFS implementations. It MAY BE REMOVED AT ANY TIME. */ + if( pBt->pPage1==0 && wrflag ){ + sqlite3_file *fd = sqlite3PagerFile(pPager); + char *aFcntl[3] = {0,0,0}; + aFcntl[1] = "experimental_pragma_20251114"; + assert( wrflag==1 || wrflag==2 ); + aFcntl[2] = (wrflag==1 ? "1" : "2"); + sqlite3OsFileControlHint(fd, SQLITE_FCNTL_PRAGMA, (void*)aFcntl); + sqlite3_free(aFcntl[0]); + } +#endif + /* Call lockBtree() until either pBt->pPage1 is populated or ** lockBtree() returns something other than SQLITE_OK. lockBtree() ** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after @@ -77556,7 +78237,7 @@ static int accessPayload( getCellInfo(pCur); aPayload = pCur->info.pPayload; - assert( offset+amt <= pCur->info.nPayload ); + assert( (u64)offset+(u64)amt <= (u64)pCur->info.nPayload ); assert( aPayload > pPage->aData ); if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){ @@ -78113,7 +78794,7 @@ SQLITE_PRIVATE int sqlite3BtreeIsEmpty(BtCursor *pCur, int *pRes){ assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); - if( pCur->eState==CURSOR_VALID ){ + if( NEVER(pCur->eState==CURSOR_VALID) ){ *pRes = 0; return SQLITE_OK; } @@ -82194,7 +82875,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 }while( rc==SQLITE_OK && nOut>0 ); if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){ - Pgno pgnoNew; + Pgno pgnoNew = 0; /* Prevent harmless static-analyzer warning */ MemPage *pNew = 0; rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0); put4byte(pPgnoOut, pgnoNew); @@ -84860,21 +85541,27 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){ StrAccum acc; assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) ); assert( sz>22 ); - if( p->flags & MEM_Int ){ -#if GCC_VERSION>=7000000 - /* Work-around for GCC bug - ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */ + if( p->flags & (MEM_Int|MEM_IntReal) ){ +#if GCC_VERSION>=7000000 && GCC_VERSION<15000000 && defined(__i386__) + /* Work-around for GCC bug or bugs: + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 + ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114659 + ** The problem appears to be fixed in GCC 15 */ i64 x; - assert( (p->flags&MEM_Int)*2==sizeof(x) ); - memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2); + assert( (MEM_Str&~p->flags)*4==sizeof(x) ); + memcpy(&x, (char*)&p->u, (MEM_Str&~p->flags)*4); p->n = sqlite3Int64ToText(x, zBuf); #else p->n = sqlite3Int64ToText(p->u.i, zBuf); #endif + if( p->flags & MEM_IntReal ){ + memcpy(zBuf+p->n,".0", 3); + p->n += 2; + } }else{ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0); - sqlite3_str_appendf(&acc, "%!.15g", - (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r); + sqlite3_str_appendf(&acc, "%!.*g", + (p->db ? p->db->nFpDigit : 17), p->u.r); assert( acc.zText==zBuf && acc.mxAlloc<=0 ); zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */ p->n = acc.nChar; @@ -84923,6 +85610,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){ assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 ); } if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1; + if( p->db==0 ){ + return 1; /* db->nFpDigit required to validate p->z[] */ + } memcpy(&tmp, p, sizeof(tmp)); vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp); z = p->z; @@ -85073,13 +85763,16 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ ** ** This is an optimization. Correct operation continues even if ** this routine is a no-op. +** +** Return true if the strig is zero-terminated after this routine is +** called and false if it is not. */ -SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ +SQLITE_PRIVATE int sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){ /* pMem must be a string, and it cannot be an ephemeral or static string */ - return; + return 0; } - if( pMem->enc!=SQLITE_UTF8 ) return; + if( pMem->enc!=SQLITE_UTF8 ) return 0; assert( pMem->z!=0 ); if( pMem->flags & MEM_Dyn ){ if( pMem->xDel==sqlite3_free @@ -85087,18 +85780,19 @@ SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } if( pMem->xDel==sqlite3RCStrUnref ){ /* Blindly assume that all RCStr objects are zero-terminated */ pMem->flags |= MEM_Term; - return; + return 1; } }else if( pMem->szMalloc >= pMem->n+1 ){ pMem->z[pMem->n] = 0; pMem->flags |= MEM_Term; - return; + return 1; } + return 0; } /* @@ -85396,18 +86090,117 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){ } } +/* +** This routine implements the uncommon and slower path for +** sqlite3MemRealValueRC() that has to deal with input strings +** that are not UTF8 or that are not zero-terminated. It is +** broken out into a separate no-inline routine so that the +** main sqlite3MemRealValueRC() routine can avoid unnecessary +** stack pushes. +** +** A text->float translation of pMem->z is written into *pValue. +** +** Result code invariants: +** +** rc==0 => ERROR: Input string not well-formed, or OOM +** rc<0 => Some prefix of the input is well-formed +** rc>0 => All of the input is well-formed +** (rc&2)==0 => The number is expressed as an integer, with no +** decimal point or eNNN suffix. +*/ +static SQLITE_NOINLINE int sqlite3MemRealValueRCSlowPath( + Mem *pMem, + double *pValue +){ + int rc = SQLITE_OK; + *pValue = 0.0; + if( pMem->enc==SQLITE_UTF8 ){ + char *zCopy = sqlite3DbStrNDup(pMem->db, pMem->z, pMem->n); + if( zCopy ){ + rc = sqlite3AtoF(zCopy, pValue); + sqlite3DbFree(pMem->db, zCopy); + } + return rc; + }else{ + int n, i, j; + char *zCopy; + const char *z; + + n = pMem->n & ~1; + zCopy = sqlite3DbMallocRaw(pMem->db, n/2 + 2); + if( zCopy ){ + z = pMem->z; + if( pMem->enc==SQLITE_UTF16LE ){ + for(i=j=0; idb, zCopy); + } + return rc; + } +} + +/* +** Invoke sqlite3AtoF() on the text value of pMem. Write the +** translation of the text input into *pValue. +** +** The caller must ensure that pMem->db!=0 and that pMem is in +** mode MEM_Str or MEM_Blob. +** +** Result code invariants: +** +** rc==0 => ERROR: Input string not well-formed, or OOM +** rc<0 => Some prefix of the input is well-formed +** rc>0 => All of the input is well-formed +** (rc&2)==0 => The number is expressed as an integer, with no +** decimal point or eNNN suffix. +*/ +SQLITE_PRIVATE int sqlite3MemRealValueRC(Mem *pMem, double *pValue){ + testcase( pMem->db==0 ); + assert( pMem->flags & (MEM_Str|MEM_Blob) ); + if( pMem->z==0 ){ + *pValue = 0.0; + return 0; + }else if( pMem->enc==SQLITE_UTF8 + && ((pMem->flags & MEM_Term)!=0 || sqlite3VdbeMemZeroTerminateIfAble(pMem)) + ){ + return sqlite3AtoF(pMem->z, pValue); + }else if( pMem->n==0 ){ + *pValue = 0.0; + return 0; + }else{ + return sqlite3MemRealValueRCSlowPath(pMem, pValue); + } +} + +/* +** This routine acts as a bridge from sqlite3VdbeRealValue() to +** sqlite3VdbeRealValueRC, allowing sqlite3VdbeRealValue() to avoid +** stuffing values onto the stack. +*/ +static SQLITE_NOINLINE double sqlite3MemRealValueNoRC(Mem *pMem){ + double r; + (void)sqlite3MemRealValueRC(pMem, &r); + return r; +} + /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its ** value. If it is a string or blob, try to convert it to a double. ** If it is a NULL, return 0.0. */ -static SQLITE_NOINLINE double memRealValue(Mem *pMem){ - /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ - double val = (double)0; - sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc); - return val; -} SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ assert( pMem!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); @@ -85418,7 +86211,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){ testcase( pMem->flags & MEM_IntReal ); return (double)pMem->u.i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - return memRealValue(pMem); + return sqlite3MemRealValueNoRC(pMem); }else{ /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ return (double)0; @@ -85542,8 +86335,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ sqlite3_int64 ix; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); - if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1) + rc = sqlite3MemRealValueRC(pMem, &pMem->u.r); + if( ((rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<2) || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r))) ){ pMem->u.i = ix; @@ -86007,6 +86800,84 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr( return SQLITE_OK; } +/* Like sqlite3VdbeMemSetStr() except: +** +** enc is always SQLITE_UTF8 +** pMem->db is always non-NULL +*/ +SQLITE_PRIVATE int sqlite3VdbeMemSetText( + Mem *pMem, /* Memory cell to set to string value */ + const char *z, /* String pointer */ + i64 n, /* Bytes in string, or negative */ + void (*xDel)(void*) /* Destructor function */ +){ + i64 nByte = n; /* New value for pMem->n */ + u16 flags; + + assert( pMem!=0 ); + assert( pMem->db!=0 ); + assert( sqlite3_mutex_held(pMem->db->mutex) ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); + + /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ + if( !z ){ + sqlite3VdbeMemSetNull(pMem); + return SQLITE_OK; + } + + if( nByte<0 ){ + nByte = strlen(z); + flags = MEM_Str|MEM_Term; + }else{ + flags = MEM_Str; + } + if( nByte>(i64)pMem->db->aLimit[SQLITE_LIMIT_LENGTH] ){ + if( xDel && xDel!=SQLITE_TRANSIENT ){ + if( xDel==SQLITE_DYNAMIC ){ + sqlite3DbFree(pMem->db, (void*)z); + }else{ + xDel((void*)z); + } + } + sqlite3VdbeMemSetNull(pMem); + return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG); + } + + /* The following block sets the new values of Mem.z and Mem.xDel. It + ** also sets a flag in local variable "flags" to indicate the memory + ** management (one of MEM_Dyn or MEM_Static). + */ + if( xDel==SQLITE_TRANSIENT ){ + i64 nAlloc = nByte + 1; + testcase( nAlloc==31 ); + testcase( nAlloc==32 ); + if( sqlite3VdbeMemClearAndResize(pMem, (int)MAX(nAlloc,32)) ){ + return SQLITE_NOMEM_BKPT; + } + assert( pMem->z!=0 ); + memcpy(pMem->z, z, nByte); + pMem->z[nByte] = 0; + }else{ + sqlite3VdbeMemRelease(pMem); + pMem->z = (char *)z; + if( xDel==SQLITE_DYNAMIC ){ + pMem->zMalloc = pMem->z; + pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); + pMem->xDel = 0; + }else if( xDel==SQLITE_STATIC ){ + pMem->xDel = xDel; + flags |= MEM_Static; + }else{ + pMem->xDel = xDel; + flags |= MEM_Dyn; + } + } + pMem->flags = flags; + pMem->n = (int)(nByte & 0x7fffffff); + pMem->enc = SQLITE_UTF8; + return SQLITE_OK; +} + /* ** Move data out of a btree key or data field and into a Mem structure. ** The data is payload from the entry that pCur is currently pointing @@ -86030,7 +86901,12 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree( ){ int rc; pMem->flags = MEM_Null; - if( sqlite3BtreeMaxRecordSize(pCur)=SQLITE_MAX_ALLOCATION_SIZE ){ + return SQLITE_NOMEM_BKPT; + } + if( (u64)amt + (u64)offset > (u64)sqlite3BtreeMaxRecordSize(pCur) ){ return SQLITE_CORRUPT_BKPT; } if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+1)) ){ @@ -86430,7 +87306,7 @@ static int valueFromExpr( if( affinity==SQLITE_AFF_BLOB ){ if( op==TK_FLOAT ){ assert( pVal && pVal->z && pVal->flags==(MEM_Str|MEM_Term) ); - sqlite3AtoF(pVal->z, &pVal->u.r, pVal->n, SQLITE_UTF8); + sqlite3AtoF(pVal->z, &pVal->u.r); pVal->flags = MEM_Real; }else if( op==TK_INTEGER ){ /* This case is required by -9223372036854775808 and other strings @@ -86698,6 +87574,11 @@ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr( ** ** If *ppVal is initially NULL then the caller is responsible for ** ensuring that the value written into *ppVal is eventually freed. +** +** If the buffer does not contain a well-formed record, this routine may +** read several bytes past the end of the buffer. Callers must therefore +** ensure that any buffer which may contain a corrupt record is padded +** with at least 8 bytes of addressable memory. */ SQLITE_PRIVATE int sqlite3Stat4Column( sqlite3 *db, /* Database handle */ @@ -88816,6 +89697,10 @@ SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){ zP4 = pOp->p4.pTab->zName; break; } + case P4_INDEX: { + zP4 = pOp->p4.pIdx->zName; + break; + } case P4_SUBRTNSIG: { SubrtnSig *pSig = pOp->p4.pSubrtnSig; sqlite3_str_appendf(&x, "subrtnsig:%d,%s", pSig->selId, pSig->zAff); @@ -89714,7 +90599,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName( } assert( p->aColName!=0 ); pColName = &(p->aColName[idx+var*p->nResAlloc]); - rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel); + rc = sqlite3VdbeMemSetText(pColName, zName, -1, xDel); assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 ); return rc; } @@ -92206,6 +93091,223 @@ SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ } } +/* +** Helper function for vdbeIsMatchingIndexKey(). Return true if column +** iCol should be ignored when comparing a record with a record from +** an index on disk. The field should be ignored if: +** +** * the corresponding bit in mask is set, and +** * either: +** - bIntegrity is false, or +** - the two Mem values are both real values that differ by +** BTREE_ULPDISTORTION or fewer ULPs. +*/ +static int vdbeSkipField( + Bitmask mask, /* Mask of indexed expression fields */ + int iCol, /* Column of index being considered */ + Mem *pMem1, /* Expected index value */ + Mem *pMem2, /* Actual indexed value */ + int bIntegrity /* True if running PRAGMA integrity_check */ +){ +#define BTREE_ULPDISTORTION 2 + if( iCol>=BMS || (mask & MASKBIT(iCol))==0 ) return 0; + if( bIntegrity==0 ) return 1; + if( (pMem1->flags & MEM_Real) && (pMem2->flags & MEM_Real) ){ + u64 m1, m2; + memcpy(&m1,&pMem1->u.r,8); + memcpy(&m2,&pMem2->u.r,8); + if( (m1pKeyInfo->enc; + mem.db = p->pKeyInfo->db; + nRec = sqlite3BtreePayloadSize(pCur); + if( nRec>0x7fffffff ){ + return SQLITE_CORRUPT_BKPT; + } + + /* Allocate 5 extra bytes at the end of the buffer. This allows the + ** getVarint32() call below to read slightly past the end of the buffer + ** if the record is corrupt. */ + aRec = sqlite3MallocZero(nRec+5); + if( aRec==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3BtreePayload(pCur, 0, nRec, aRec); + } + + if( rc==SQLITE_OK ){ + u32 szHdr = 0; /* Size of record header in bytes */ + u32 idxHdr = 0; /* Current index in header */ + + idxHdr = getVarint32(aRec, szHdr); + if( szHdr>98307 ){ + rc = SQLITE_CORRUPT; + }else{ + int res = 0; /* Result of this function call */ + u32 idxRec = szHdr; /* Index of next field in record body */ + int ii = 0; /* Iterator variable */ + + int nCol = p->pKeyInfo->nAllField; + for(ii=0; ii=szHdr ){ + rc = SQLITE_CORRUPT_BKPT; + break; + } + idxHdr += getVarint32(&aRec[idxHdr], iSerial); + nSerial = sqlite3VdbeSerialTypeLen(iSerial); + if( (idxRec+nSerial)>nRec ){ + rc = SQLITE_CORRUPT_BKPT; + }else{ + sqlite3VdbeSerialGet(&aRec[idxRec], iSerial, &mem); + if( vdbeSkipField(mask, ii, &p->aMem[ii], &mem, bInt)==0 ){ + res = sqlite3MemCompare(&mem, &p->aMem[ii], p->pKeyInfo->aColl[ii]); + if( res!=0 ) break; + } + } + idxRec += sqlite3VdbeSerialTypeLen(iSerial); + } + + *piRes = res; + } + } + + sqlite3_free(aRec); + return rc; +} + +/* +** This is called when the record in (*p) should be found in the index +** opened by cursor pCur, but was not. This may happen as part of a DELETE +** operation or an integrity check. +** +** One reason that an exact match was not found may be the EIIB bug - that +** a text-to-float conversion may have caused a real value in record (*p) +** to be slightly different from its counterpart on disk. This function +** attempts to find the right index record. If it does find the right +** record, it leaves *pCur pointing to it and sets (*pRes) to 0 before +** returning. Otherwise, (*pRes) is set to non-zero and an SQLite error +** code returned. +** +** The algorithm used to find the correct record is: +** +** * Scan up to BTREE_FDK_RANGE entries either side of the current entry. +** If parameter bIntegrity is false, then all fields that are indexed +** expressions or virtual table columns are omitted from the comparison. +** If bIntegrity is true, then small differences in real values in +** such fields are overlooked, but they are not omitted from the comparison +** altogether. +** +** * If the above fails to find an entry and bIntegrity is false, search +** the entire index. +*/ +SQLITE_PRIVATE int sqlite3VdbeFindIndexKey( + BtCursor *pCur, + Index *pIdx, + UnpackedRecord *p, + int *pRes, + int bIntegrity +){ +#define BTREE_FDK_RANGE 10 + int nStep = 0; + int res = 1; + int rc = SQLITE_OK; + int ii = 0; + + /* Calculate a mask based on the first 64 columns of the index. The mask + ** bit is set if the corresponding index field is either an expression + ** or a virtual column of the table. */ + Bitmask mask = 0; + for(ii=0; iinColumn, BMS); ii++){ + int iCol = pIdx->aiColumn[ii]; + if( (iCol==XN_EXPR) + || (iCol>=0 && (pIdx->pTable->aCol[iCol].colFlags & COLFLAG_VIRTUAL)) + ){ + mask |= MASKBIT(ii); + } + } + + /* If the mask is 0 at this point, then the index contains no expressions + ** or virtual columns. So do not search for a match - return so that the + ** caller may declare the db corrupt immediately. Or, if mask is non-zero, + ** proceed. */ + if( mask!=0 ){ + + /* Move the cursor back BTREE_FDK_RANGE entries. If this hits an EOF, + ** position the cursor at the first entry in the index and set nStep + ** to -1 so that the first loop below scans the entire index. Otherwise, + ** set nStep to BTREE_FDK_RANGE*2 so that the first loop below scans + ** just that many entries. */ + for(ii=0; sqlite3BtreeEof(pCur)==0 && ii=0), or the entire index if (nStep<0). */ + while( sqlite3BtreeCursorIsValidNN(pCur) ){ + for(ii=0; rc==SQLITE_OK && (iipOut; - int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel); + int rc; + if( enc==SQLITE_UTF8 ){ + rc = sqlite3VdbeMemSetText(pOut, z, n, xDel); + }else if( enc==SQLITE_UTF8_ZT ){ + /* It is usually considered improper to assert() on an input. However, + ** the following assert() is checking for inputs that are documented + ** to result in undefined behavior. */ + assert( z==0 + || n<0 + || n>pOut->db->aLimit[SQLITE_LIMIT_LENGTH] + || z[n]==0 + ); + rc = sqlite3VdbeMemSetText(pOut, z, n, xDel); + pOut->flags |= MEM_Term; + }else{ + rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel); + } if( rc ){ if( rc==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); @@ -92985,7 +94103,7 @@ SQLITE_API void sqlite3_result_text64( #endif assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF8_ZT ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; n &= ~(u64)1; } @@ -93136,6 +94254,8 @@ static int doWalCallbacks(sqlite3 *db){ } } } +#else + UNUSED_PARAMETER(db); #endif return rc; } @@ -93443,7 +94563,7 @@ static int valueFromValueList( Mem sMem; /* Raw content of current row */ memset(&sMem, 0, sizeof(sMem)); sz = sqlite3BtreePayloadSize(pRhs->pCsr); - rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem); + rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,sz,&sMem); if( rc==SQLITE_OK ){ u8 *zBuf = (u8*)sMem.z; u32 iSerial; @@ -94092,13 +95212,25 @@ static int bindText( assert( p!=0 && p->aVar!=0 && i>0 && i<=p->nVar ); /* tag-20240917-01 */ if( zData!=0 ){ pVar = &p->aVar[i-1]; - rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); - if( rc==SQLITE_OK ){ - if( encoding==0 ){ - pVar->enc = ENC(p->db); - }else{ - rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); - } + if( encoding==SQLITE_UTF8 ){ + rc = sqlite3VdbeMemSetText(pVar, zData, nData, xDel); + }else if( encoding==SQLITE_UTF8_ZT ){ + /* It is usually consider improper to assert() on an input. + ** However, the following assert() is checking for inputs + ** that are documented to result in undefined behavior. */ + assert( zData==0 + || nData<0 + || nData>pVar->db->aLimit[SQLITE_LIMIT_LENGTH] + || ((u8*)zData)[nData]==0 + ); + rc = sqlite3VdbeMemSetText(pVar, zData, nData, xDel); + pVar->flags |= MEM_Term; + }else{ + rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); + if( encoding==0 ) pVar->enc = ENC(p->db); + } + if( rc==SQLITE_OK && encoding!=0 ){ + rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } if( rc ){ sqlite3Error(p->db, rc); @@ -94210,7 +95342,7 @@ SQLITE_API int sqlite3_bind_text64( unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); - if( enc!=SQLITE_UTF8 ){ + if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF8_ZT ){ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; nData &= ~(u64)1; } @@ -95247,17 +96379,19 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( #ifndef SQLITE_HWTIME_H #define SQLITE_HWTIME_H -/* -** The following routine only works on Pentium-class (or newer) processors. -** It uses the RDTSC opcode to read the cycle count value out of the -** processor and returns that value. This can be used for high-res -** profiling. -*/ -#if !defined(__STRICT_ANSI__) && \ - (defined(__GNUC__) || defined(_MSC_VER)) && \ - (defined(i386) || defined(__i386__) || defined(_M_IX86)) +#if defined(_MSC_VER) && defined(_WIN32) - #if defined(__GNUC__) +/* #include "windows.h" */ + #include + + __inline sqlite3_uint64 sqlite3Hwtime(void){ + LARGE_INTEGER tm; + QueryPerformanceCounter(&tm); + return (sqlite3_uint64)tm.QuadPart; + } + +#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && \ + (defined(i386) || defined(__i386__) || defined(_M_IX86)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned int lo, hi; @@ -95265,17 +96399,6 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( return (sqlite_uint64)hi << 32 | lo; } - #elif defined(_MSC_VER) - - __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){ - __asm { - rdtsc - ret ; return value at EDX:EAX - } - } - - #endif - #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ @@ -95284,6 +96407,14 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql( return (sqlite_uint64)hi << 32 | lo; } +#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__aarch64__) + + __inline__ sqlite_uint64 sqlite3Hwtime(void){ + sqlite3_uint64 cnt; + __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (cnt)); + return cnt; + } + #elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ @@ -95642,12 +96773,11 @@ static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){ */ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ double rValue; - u8 enc = pRec->enc; int rc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real|MEM_IntReal))==MEM_Str ); - rc = sqlite3AtoF(pRec->z, &rValue, pRec->n, enc); + rc = sqlite3MemRealValueRC(pRec, &rValue); if( rc<=0 ) return; - if( rc==1 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ + if( (rc&2)==0 && alsoAnInt(pRec, rValue, &pRec->u.i) ){ pRec->flags |= MEM_Int; }else{ pRec->u.r = rValue; @@ -95727,7 +96857,10 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){ int eType = sqlite3_value_type(pVal); if( eType==SQLITE_TEXT ){ Mem *pMem = (Mem*)pVal; + assert( pMem->db!=0 ); + sqlite3_mutex_enter(pMem->db->mutex); applyNumericAffinity(pMem, 0); + sqlite3_mutex_leave(pMem->db->mutex); eType = sqlite3_value_type(pVal); } return eType; @@ -95760,15 +96893,15 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ pMem->u.i = 0; return MEM_Int; } - rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + rc = sqlite3MemRealValueRC(pMem, &pMem->u.r); if( rc<=0 ){ - if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ + if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){ pMem->u.i = ix; return MEM_Int; }else{ return MEM_Real; } - }else if( rc==1 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ + }else if( (rc&2)==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)==0 ){ pMem->u.i = ix; return MEM_Int; } @@ -101909,20 +103042,17 @@ case OP_SorterInsert: { /* in2 */ break; } -/* Opcode: IdxDelete P1 P2 P3 * P5 +/* Opcode: IdxDelete P1 P2 P3 P4 * ** Synopsis: key=r[P2@P3] ** ** The content of P3 registers starting at register P2 form ** an unpacked index key. This opcode removes that entry from the ** index opened by cursor P1. ** -** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error -** if no matching index entry is found. This happens when running -** an UPDATE or DELETE statement and the index entry to be updated -** or deleted is not found. For some uses of IdxDelete -** (example: the EXCEPT operator) it does not matter that no matching -** entry is found. For those cases, P5 is zero. Also, do not raise -** this (self-correcting and non-critical) error if in writable_schema mode. +** P4 is a pointer to an Index structure. +** +** Raise an SQLITE_CORRUPT_INDEX error if no matching index entry is found +** and not in writable_schema mode. */ case OP_IdxDelete: { VdbeCursor *pC; @@ -101945,13 +103075,22 @@ case OP_IdxDelete: { r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res); if( rc ) goto abort_due_to_error; - if( res==0 ){ - rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); - if( rc ) goto abort_due_to_error; - }else if( pOp->p5 && !sqlite3WritableSchema(db) ){ - rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); - goto abort_due_to_error; + if( res!=0 ){ + rc = sqlite3VdbeFindIndexKey(pCrsr, pOp->p4.pIdx, &r, &res, 0); + if( rc!=SQLITE_OK ) goto abort_due_to_error; + if( res!=0 ){ + if( !sqlite3WritableSchema(db) ){ + rc = sqlite3ReportError( + SQLITE_CORRUPT_INDEX, __LINE__, "index corruption"); + goto abort_due_to_error; + } + pC->cacheStatus = CACHE_STALE; + pC->seekResult = 0; + break; + } } + rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); + if( rc ) goto abort_due_to_error; assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; @@ -102578,6 +103717,58 @@ case OP_IntegrityCk: { sqlite3VdbeChangeEncoding(pIn1, encoding); goto check_for_interrupt; } + +/* Opcode: IFindKey P1 P2 P3 P4 * +** +** This instruction always follows an OP_Found with the same P1, P2 and P3 +** values as this instruction and a non-zero P4 value. The P4 value to +** this opcode is of type P4_INDEX and contains a pointer to the Index +** object of for the index being searched. +** +** This opcode uses sqlite3VdbeFindIndexKey() to search around the current +** cursor location for an index key that exactly matches all fields that +** are not indexed expressions or references to VIRTUAL generated columns, +** and either exactly match or are real numbers that are within 2 ULPs of +** each other if the don't match. +** +** To put it another way, this opcode looks for nearby index entries that +** are very close to the search key, but which might have small differences +** in floating-point values that come via an expression. +** +** If no nearby alternative entry is found in cursor P1, then jump to P2. +** But if a close match is found, fall through. +** +** This opcode is used by PRAGMA integrity_check to help distinguish +** between truely corrupt indexes and expression indexes that are holding +** floating-point values that are off by one or two ULPs. +*/ +case OP_IFindKey: { /* jump, in3 */ + VdbeCursor *pC; + int res; + UnpackedRecord r; + + assert( pOp[-1].opcode==OP_Found ); + assert( pOp[-1].p1==pOp->p1 ); + assert( pOp[-1].p3==pOp->p3 ); + pC = p->apCsr[pOp->p1]; + assert( pOp->p4type==P4_INDEX ); + assert( pC->eCurType==CURTYPE_BTREE ); + assert( pC->uc.pCursor!=0 ); + assert( pC->isTable==0 ); + + memset(&r, 0, sizeof(r)); + r.aMem = &aMem[pOp->p3]; + r.nField = pOp->p4.pIdx->nColumn; + r.pKeyInfo = pC->pKeyInfo; + + rc = sqlite3VdbeFindIndexKey(pC->uc.pCursor, pOp->p4.pIdx, &r, &res, 1); + if( rc || res!=0 ){ + rc = SQLITE_OK; + goto jump_to_p2; + } + pC->nullRow = 0; + break; +}; #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* Opcode: RowSetAdd P1 P2 * * * @@ -110042,7 +111233,7 @@ static int exprProbability(Expr *p){ double r = -1.0; if( p->op!=TK_FLOAT ) return -1; assert( !ExprHasProperty(p, EP_IntValue) ); - sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8); + sqlite3AtoF(p->u.zToken, &r); assert( r>=0.0 ); if( r>1.0 ) return -1; return (int)(r*134217728.0); @@ -110762,10 +111953,8 @@ static int resolveCompoundOrderBy( /* Convert the ORDER BY term into an integer column number iCol, ** taking care to preserve the COLLATE clause if it exists. */ if( !IN_RENAME_OBJECT ){ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pNew = sqlite3ExprInt32(db, iCol); if( pNew==0 ) return 1; - pNew->flags |= EP_IntValue; - pNew->u.iValue = iCol; if( pItem->pExpr==pE ){ pItem->pExpr = pNew; }else{ @@ -111119,10 +112308,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ } #endif - /* The ORDER BY and GROUP BY clauses may not refer to terms in - ** outer queries - */ - sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; /* If this is a converted compound query, move the ORDER BY clause from @@ -111185,6 +112370,14 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ return WRC_Abort; } + /* If the SELECT statement contains ON clauses that were moved into + ** the WHERE clause, go through and verify that none of the terms + ** in the ON clauses reference tables to the right of the ON clause. */ + if( (p->selFlags & SF_OnToWhere) ){ + sqlite3SelectCheckOnClauses(pParse, p); + if( pParse->nErr ) return WRC_Abort; + } + /* Advance to the next term of the compound */ p = p->pPrior; @@ -112361,34 +113554,22 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc( int dequote /* True to dequote */ ){ Expr *pNew; - int nExtra = 0; - int iValue = 0; + int nExtra = pToken ? pToken->n+1 : 0; assert( db!=0 ); - if( pToken ){ - if( op!=TK_INTEGER || pToken->z==0 - || sqlite3GetInt32(pToken->z, &iValue)==0 ){ - nExtra = pToken->n+1; /* tag-20240227-a */ - assert( iValue>=0 ); - } - } pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)+nExtra); if( pNew ){ memset(pNew, 0, sizeof(Expr)); pNew->op = (u8)op; pNew->iAgg = -1; - if( pToken ){ - if( nExtra==0 ){ - pNew->flags |= EP_IntValue|EP_Leaf|(iValue?EP_IsTrue:EP_IsFalse); - pNew->u.iValue = iValue; - }else{ - pNew->u.zToken = (char*)&pNew[1]; - assert( pToken->z!=0 || pToken->n==0 ); - if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); - pNew->u.zToken[pToken->n] = 0; - if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ - sqlite3DequoteExpr(pNew); - } + if( nExtra ){ + assert( pToken!=0 ); + pNew->u.zToken = (char*)&pNew[1]; + assert( pToken->z!=0 || pToken->n==0 ); + if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n); + pNew->u.zToken[pToken->n] = 0; + if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){ + sqlite3DequoteExpr(pNew); } } #if SQLITE_MAX_EXPR_DEPTH>0 @@ -112413,6 +113594,24 @@ SQLITE_PRIVATE Expr *sqlite3Expr( return sqlite3ExprAlloc(db, op, &x, 0); } +/* +** Allocate an expression for a 32-bit signed integer literal. +*/ +SQLITE_PRIVATE Expr *sqlite3ExprInt32(sqlite3 *db, int iVal){ + Expr *pNew = sqlite3DbMallocRawNN(db, sizeof(Expr)); + if( pNew ){ + memset(pNew, 0, sizeof(Expr)); + pNew->op = TK_INTEGER; + pNew->iAgg = -1; + pNew->flags = EP_IntValue|EP_Leaf|(iVal?EP_IsTrue:EP_IsFalse); + pNew->u.iValue = iVal; +#if SQLITE_MAX_EXPR_DEPTH>0 + pNew->nHeight = 1; +#endif + } + return pNew; +} + /* ** Attach subtrees pLeft and pRight to the Expr node pRoot. ** @@ -112575,7 +113774,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ ){ sqlite3ExprDeferredDelete(pParse, pLeft); sqlite3ExprDeferredDelete(pParse, pRight); - return sqlite3Expr(db, TK_INTEGER, "0"); + return sqlite3ExprInt32(db, 0); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); } @@ -112700,7 +113899,9 @@ SQLITE_PRIVATE void sqlite3ExprFunctionUsable( ){ assert( !IN_RENAME_OBJECT ); assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 ); - if( ExprHasProperty(pExpr, EP_FromDDL) ){ + if( ExprHasProperty(pExpr, EP_FromDDL) + || pParse->prepFlags & SQLITE_PREPARE_FROM_DDL + ){ if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0 || (pParse->db->flags & SQLITE_TrustedSchema)==0 ){ @@ -113396,9 +114597,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int fla pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags); pNew->iLimit = 0; pNew->iOffset = 0; - pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral; - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; + pNew->selFlags = p->selFlags; pNew->nSelectRow = p->nSelectRow; pNew->pWith = sqlite3WithDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC @@ -114050,7 +115249,7 @@ static int exprIsConst(Parse *pParse, Expr *p, int initFlag){ /* ** Walk an expression tree. Return non-zero if the expression is constant -** and 0 if it involves variables or function calls. +** or return zero if the expression involves variables or function calls. ** ** For the purposes of this function, a double-quoted string (ex: "abc") ** is considered a variable but a single-quoted string (ex: 'abc') is @@ -114840,6 +116039,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex( */ u32 savedNQueryLoop = pParse->nQueryLoop; int rMayHaveNull = 0; + int bloomOk = (inFlags & IN_INDEX_MEMBERSHIP)!=0; eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; @@ -114847,7 +116047,13 @@ SQLITE_PRIVATE int sqlite3FindInIndex( *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } assert( pX->op==TK_IN ); - sqlite3CodeRhsOfIN(pParse, pX, iTab); + if( !bloomOk + && ExprUseXSelect(pX) + && (pX->x.pSelect->selFlags & SF_ClonedRhsIn)!=0 + ){ + bloomOk = 1; + } + sqlite3CodeRhsOfIN(pParse, pX, iTab, bloomOk); if( rMayHaveNull ){ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); } @@ -115005,7 +116211,8 @@ static int findCompatibleInRhsSubrtn( SQLITE_PRIVATE void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN operator */ - int iTab /* Use this cursor number */ + int iTab, /* Use this cursor number */ + int allowBloom /* True to allow the use of a Bloom filter */ ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ @@ -115127,7 +116334,10 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN( sqlite3SelectDestInit(&dest, SRT_Set, iTab); dest.zAffSdst = exprINAffinity(pParse, pExpr); pSelect->iLimit = 0; - if( addrOnce && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){ + if( addrOnce + && allowBloom + && OptimizationEnabled(pParse->db, SQLITE_BloomFilter) + ){ int regBloom = ++pParse->nMem; addrBloom = sqlite3VdbeAddOp2(v, OP_Blob, 10000, regBloom); VdbeComment((v, "Bloom filter")); @@ -115348,7 +116558,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ || (pLeft->u.iValue!=1 && pLeft->u.iValue!=0) ){ sqlite3 *db = pParse->db; - pLimit = sqlite3Expr(db, TK_INTEGER, "0"); + pLimit = sqlite3ExprInt32(db, 0); if( pLimit ){ pLimit->affExpr = SQLITE_AFF_NUMERIC; pLimit = sqlite3PExpr(pParse, TK_NE, @@ -115359,7 +116569,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } }else{ /* If there is no pre-existing limit add a limit of 1 */ - pLimit = sqlite3Expr(pParse->db, TK_INTEGER, "1"); + pLimit = sqlite3ExprInt32(pParse->db, 1); pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; @@ -115620,8 +116830,9 @@ static void sqlite3ExprCodeIN( if( ExprHasProperty(pExpr, EP_Subrtn) ){ const VdbeOp *pOp = sqlite3VdbeGetOp(v, pExpr->y.sub.iAddr); assert( pOp->opcode==OP_Once || pParse->nErr ); - if( pOp->opcode==OP_Once && pOp->p3>0 ){ /* tag-202407032019 */ - assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ); + if( pOp->p3>0 ){ /* tag-202407032019 */ + assert( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) + || pParse->nErr ); sqlite3VdbeAddOp4Int(v, OP_Filter, pOp->p3, destIfFalse, rLhs, nVector); VdbeCoverage(v); } @@ -115711,7 +116922,7 @@ sqlite3ExprCodeIN_oom_error: static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; - sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); + sqlite3AtoF(z, &value); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; sqlite3VdbeAddOp4Dup8(v, OP_Real, 0, iMem, 0, (u8*)&value, P4_REAL); @@ -116570,7 +117781,7 @@ expr_code_doover: case TK_ISNOT: op = (op==TK_IS) ? TK_EQ : TK_NE; p5 = SQLITE_NULLEQ; - /* fall-through */ + /* no break */ deliberate_fall_through case TK_LT: case TK_LE: case TK_GT: @@ -118812,7 +120023,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){ if( pIEpr==0 ) break; if( NEVER(!ExprUseYTab(pExpr)) ) break; for(i=0; inSrc; i++){ - if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break; + if( pSrcList->a[i].iCursor==pIEpr->iDataCur ){ + testcase( i>0 ); + break; + } } if( i>=pSrcList->nSrc ) break; if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */ @@ -119601,7 +120815,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){ /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); assert( sqlite3BtreeHoldsAllMutexes(db) ); - if( db->mallocFailed ) goto exit_begin_add_column; + if( NEVER(db->mallocFailed) ) goto exit_begin_add_column; pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); if( !pTab ) goto exit_begin_add_column; @@ -119673,7 +120887,7 @@ exit_begin_add_column: ** Or, if pTab is not a view or virtual table, zero is returned. */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) -static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ +static int isRealTable(Parse *pParse, Table *pTab, int iOp){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( IsView(pTab) ){ @@ -119686,9 +120900,12 @@ static int isRealTable(Parse *pParse, Table *pTab, int bDrop){ } #endif if( zType ){ + const char *azMsg[] = { + "rename columns of", "drop column from", "edit constraints of" + }; + assert( iOp>=0 && iOpzName + azMsg[iOp], zType, pTab->zName ); return 1; } @@ -120159,6 +121376,25 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){ return pBest; } +/* +** Set the error message of the context passed as the first argument to +** the result of formatting zFmt using printf() style formatting. +*/ +static void errorMPrintf(sqlite3_context *pCtx, const char *zFmt, ...){ + sqlite3 *db = sqlite3_context_db_handle(pCtx); + char *zErr = 0; + va_list ap; + va_start(ap, zFmt); + zErr = sqlite3VMPrintf(db, zFmt, ap); + va_end(ap); + if( zErr ){ + sqlite3_result_error(pCtx, zErr, -1); + sqlite3DbFree(db, zErr); + }else{ + sqlite3_result_error_nomem(pCtx); + } +} + /* ** An error occurred while parsing or otherwise processing a database ** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an @@ -120456,8 +121692,8 @@ static int renameResolveTrigger(Parse *pParse){ sqlite3SelectPrep(pParse, pStep->pSelect, &sNC); if( pParse->nErr ) rc = pParse->rc; } - if( rc==SQLITE_OK && pStep->zTarget ){ - SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); + if( rc==SQLITE_OK && pStep->pSrc ){ + SrcList *pSrc = sqlite3SrcListDup(db, pStep->pSrc, 0); if( pSrc ){ Select *pSel = sqlite3SelectNew( pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0 @@ -120485,10 +121721,10 @@ static int renameResolveTrigger(Parse *pParse){ pSel->pSrc = 0; sqlite3SelectDelete(db, pSel); } - if( pStep->pFrom ){ + if( ALWAYS(pStep->pSrc) ){ int i; - for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ - SrcItem *p = &pStep->pFrom->a[i]; + for(i=0; ipSrc->nSrc && rc==SQLITE_OK; i++){ + SrcItem *p = &pStep->pSrc->a[i]; if( p->fg.isSubquery ){ assert( p->u4.pSubq!=0 ); sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0); @@ -120557,13 +121793,13 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){ sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } - if( pStep->pFrom ){ + if( pStep->pSrc ){ int i; - SrcList *pFrom = pStep->pFrom; - for(i=0; inSrc; i++){ - if( pFrom->a[i].fg.isSubquery ){ - assert( pFrom->a[i].u4.pSubq!=0 ); - sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect); + SrcList *pSrc = pStep->pSrc; + for(i=0; inSrc; i++){ + if( pSrc->a[i].fg.isSubquery ){ + assert( pSrc->a[i].u4.pSubq!=0 ); + sqlite3WalkSelect(pWalker, pSrc->a[i].u4.pSubq->pSelect); } } } @@ -120734,8 +121970,8 @@ static void renameColumnFunc( if( rc!=SQLITE_OK ) goto renameColumnFunc_done; for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget ){ - Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb); + if( pStep->pSrc ){ + Table *pTarget = sqlite3LocateTableItem(&sParse, 0, &pStep->pSrc->a[0]); if( pTarget==pTab ){ if( pStep->pUpsert ){ ExprList *pUpsertSet = pStep->pUpsert->pUpsertSet; @@ -120747,7 +121983,6 @@ static void renameColumnFunc( } } - /* Find tokens to edit in UPDATE OF clause */ if( sParse.pTriggerTab==pTab ){ renameColumnIdlistNames(&sParse, &sCtx,sParse.pNewTrigger->pColumns,zOld); @@ -120949,13 +122184,10 @@ static void renameTableFunc( if( rc==SQLITE_OK ){ renameWalkTrigger(&sWalker, pTrigger); for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ - renameTokenFind(&sParse, &sCtx, pStep->zTarget); - } - if( pStep->pFrom ){ + if( pStep->pSrc ){ int i; - for(i=0; ipFrom->nSrc; i++){ - SrcItem *pItem = &pStep->pFrom->a[i]; + for(i=0; ipSrc->nSrc; i++){ + SrcItem *pItem = &pStep->pSrc->a[i]; if( 0==sqlite3_stricmp(pItem->zName, zOld) ){ renameTokenFind(&sParse, &sCtx, pItem->zName); } @@ -121202,6 +122434,57 @@ static void renameTableTest( #endif } + +/* +** Return the number of bytes until the end of the next non-whitespace and +** non-comment token. For the purpose of this function, a "(" token includes +** all of the bytes through and including the matching ")", or until the +** first illegal token, whichever comes first. +** +** Write the token type into *piToken. +** +** The value returned is the number of bytes in the token itself plus +** the number of bytes of leading whitespace and comments skipped plus +** all bytes through the next matching ")" if the token is TK_LP. +** +** Example: (Note: '.' used in place of '*' in the example z[] text) +** +** ,--------- *piToken := TK_RP +** v +** z[] = " /.comment./ --comment\n (two three four) five" +** | | +** |<-------------------------------------->| +** | +** `--- return value +*/ +static int getConstraintToken(const u8 *z, int *piToken){ + int iOff = 0; + int t = 0; + do { + iOff += sqlite3GetToken(&z[iOff], &t); + }while( t==TK_SPACE || t==TK_COMMENT ); + + *piToken = t; + + if( t==TK_LP ){ + int nNest = 1; + while( nNest>0 ){ + iOff += sqlite3GetToken(&z[iOff], &t); + if( t==TK_LP ){ + nNest++; + }else if( t==TK_RP ){ + t = TK_LP; + nNest--; + }else if( t==TK_ILLEGAL ){ + break; + } + } + } + + *piToken = t; + return iOff; +} + /* ** The implementation of internal UDF sqlite_drop_column(). ** @@ -121246,15 +122529,24 @@ static void dropColumnFunc( goto drop_column_done; } - pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); if( iColnCol-1 ){ RenameToken *pEnd; + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName); pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName); zEnd = (const char*)pEnd->t.z; }else{ + int eTok; assert( IsOrdinaryTable(pTab) ); + assert( iCol!=0 ); + /* Point pCol->t.z at the "," immediately preceding the definition of + ** the column being dropped. To do this, start at the name of the + ** previous column, and tokenize until the next ",". */ + pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol-1].zCnName); + do { + pCol->t.z += getConstraintToken((const u8*)pCol->t.z, &eTok); + }while( eTok!=TK_COMMA ); + pCol->t.z--; zEnd = (const char*)&zSql[pTab->u.tab.addColOffset]; - while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--; } zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd); @@ -121423,6 +122715,651 @@ exit_drop_column: sqlite3SrcListDelete(db, pSrc); } +/* +** Return the number of bytes of leading whitespace/comments in string z[]. +*/ +static int getWhitespace(const u8 *z){ + int nRet = 0; + while( 1 ){ + int t = 0; + int n = sqlite3GetToken(&z[nRet], &t); + if( t!=TK_SPACE && t!=TK_COMMENT ) break; + nRet += n; + } + return nRet; +} + + +/* +** Argument z points into the body of a constraint - specifically the +** second token of the constraint definition. For a named constraint, +** z points to the first token past the CONSTRAINT keyword. For an +** unnamed NOT NULL constraint, z points to the first byte past the NOT +** keyword. +** +** Return the number of bytes until the end of the constraint. +*/ +static int getConstraint(const u8 *z){ + int iOff = 0; + int t = 0; + + /* Now, the current constraint proceeds until the next occurence of one + ** of the following tokens: + ** + ** CONSTRAINT, PRIMARY, NOT, UNIQUE, CHECK, DEFAULT, + ** COLLATE, REFERENCES, FOREIGN, GENERATED, AS, RP, or COMMA + ** + ** Also exit the loop if ILLEGAL turns up. + */ + while( 1 ){ + int n = getConstraintToken(&z[iOff], &t); + if( t==TK_CONSTRAINT || t==TK_PRIMARY || t==TK_NOT || t==TK_UNIQUE + || t==TK_CHECK || t==TK_DEFAULT || t==TK_COLLATE || t==TK_REFERENCES + || t==TK_FOREIGN || t==TK_RP || t==TK_COMMA || t==TK_ILLEGAL + || t==TK_AS || t==TK_GENERATED + ){ + break; + } + iOff += n; + } + + return iOff; +} + +/* +** Compare two constraint names. +** +** Summary: *pRes := zQuote != zCmp +** +** Details: +** Compare the (possibly quoted) constraint name zQuote[0..nQuote-1] +** against zCmp[]. Write zero into *pRes if they are the same and +** non-zero if they differ. Normally return SQLITE_OK, except if there +** is an OOM, set the OOM error condition on ctx and return SQLITE_NOMEM. +*/ +static int quotedCompare( + sqlite3_context *ctx, /* Function context on which to report errors */ + int t, /* Token type */ + const u8 *zQuote, /* Possibly quoted text. Not zero-terminated. */ + int nQuote, /* Length of zQuote in bytes */ + const u8 *zCmp, /* Zero-terminated, unquoted name to compare against */ + int *pRes /* OUT: Set to 0 if equal, non-zero if unequal */ +){ + char *zCopy = 0; /* De-quoted, zero-terminated copy of zQuote[] */ + + if( t==TK_ILLEGAL ){ + *pRes = 1; + return SQLITE_OK; + } + zCopy = sqlite3MallocZero(nQuote+1); + if( zCopy==0 ){ + sqlite3_result_error_nomem(ctx); + return SQLITE_NOMEM_BKPT; + } + memcpy(zCopy, zQuote, nQuote); + sqlite3Dequote(zCopy); + *pRes = sqlite3_stricmp((const char*)zCopy, (const char*)zCmp); + sqlite3_free(zCopy); + return SQLITE_OK; +} + +/* +** zSql[] is a CREATE TABLE statement, supposedly. Find the offset +** into zSql[] of the first character past the first "(" and write +** that offset into *piOff and return SQLITE_OK. Or, if not found, +** set the SQLITE_CORRUPT error code and return SQLITE_ERROR. +*/ +static int skipCreateTable(sqlite3_context *ctx, const u8 *zSql, int *piOff){ + int iOff = 0; + + if( zSql==0 ) return SQLITE_ERROR; + + /* Jump past the "CREATE TABLE" bit. */ + while( 1 ){ + int t = 0; + iOff += sqlite3GetToken(&zSql[iOff], &t); + if( t==TK_LP ) break; + if( t==TK_ILLEGAL ){ + sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT); + return SQLITE_ERROR; + } + } + + *piOff = iOff; + return SQLITE_OK; +} + +/* +** Internal SQL function sqlite3_drop_constraint(): Given an input +** CREATE TABLE statement, return a revised CREATE TABLE statement +** with a constraint removed. Two forms, depending on the datatype +** of argv[2]: +** +** sqlite_drop_constraint(SQL, INT) -- Omit NOT NULL from the INT-th column +** sqlite_drop_constraint(SQL, TEXT) -- OMIT constraint with name TEXT +** +** In the first case, the left-most column is 0. +*/ +static void dropConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = sqlite3_value_text(argv[0]); + const u8 *zCons = 0; + int iNotNull = -1; + int ii; + int iOff = 0; + int iStart = 0; + int iEnd = 0; + char *zNew = 0; + int t = 0; + sqlite3 *db; + UNUSED_PARAMETER(NotUsed); + + if( zSql==0 ) return; + + /* Jump past the "CREATE TABLE" bit. */ + if( skipCreateTable(ctx, zSql, &iOff) ) return; + + if( sqlite3_value_type(argv[1])==SQLITE_INTEGER ){ + iNotNull = sqlite3_value_int(argv[1]); + }else{ + zCons = sqlite3_value_text(argv[1]); + } + + /* Search for the named constraint within column definitions. */ + for(ii=0; iEnd==0; ii++){ + + /* Now parse the column or table constraint definition. Search + ** for the token CONSTRAINT if this is a DROP CONSTRAINT command, or + ** NOT in the right column if this is a DROP NOT NULL. */ + while( 1 ){ + iStart = iOff; + iOff += getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT && (zCons || iNotNull==ii) ){ + /* Check if this is the constraint we are searching for. */ + int nTok = 0; + int cmp = 1; + + /* Skip past any whitespace. */ + iOff += getWhitespace(&zSql[iOff]); + + /* Compare the next token - which may be quoted - with the name of + ** the constraint being dropped. */ + nTok = getConstraintToken(&zSql[iOff], &t); + if( zCons ){ + if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return; + } + iOff += nTok; + + /* The next token is usually the first token of the constraint + ** definition. This is enough to tell the type of the constraint - + ** TK_NOT means it is a NOT NULL, TK_CHECK a CHECK constraint etc. + ** + ** There is also the chance that the next token is TK_CONSTRAINT + ** (or TK_DEFAULT or TK_COLLATE), for example if a table has been + ** created as follows: + ** + ** CREATE TABLE t1(cols, CONSTRAINT one CONSTRAINT two NOT NULL); + ** + ** In this case, allow the "CONSTRAINT one" bit to be dropped by + ** this command if that is what is requested, or to advance to + ** the next iteration of the loop with &zSql[iOff] still pointing + ** to the CONSTRAINT keyword. */ + nTok = getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT || t==TK_DEFAULT || t==TK_COLLATE + || t==TK_COMMA || t==TK_RP || t==TK_GENERATED || t==TK_AS + ){ + t = TK_CHECK; + }else{ + iOff += nTok; + iOff += getConstraint(&zSql[iOff]); + } + + if( cmp==0 || (iNotNull>=0 && t==TK_NOT) ){ + if( t!=TK_NOT && t!=TK_CHECK ){ + errorMPrintf(ctx, "constraint may not be dropped: %s", zCons); + return; + } + iEnd = iOff; + break; + } + + }else if( t==TK_NOT && iNotNull==ii ){ + iEnd = iOff + getConstraint(&zSql[iOff]); + break; + }else if( t==TK_RP || t==TK_ILLEGAL ){ + iEnd = -1; + break; + }else if( t==TK_COMMA ){ + break; + } + } + } + + /* If the constraint has not been found it is an error. */ + if( iEnd<=0 ){ + if( zCons ){ + errorMPrintf(ctx, "no such constraint: %s", zCons); + }else{ + /* SQLite follows postgres in that a DROP NOT NULL on a column that is + ** not NOT NULL is not an error. So just return the original SQL here. */ + sqlite3_result_text(ctx, (const char*)zSql, -1, SQLITE_TRANSIENT); + } + }else{ + + /* Figure out if an extra space should be inserted after the constraint + ** is removed. And if an additional comma preceding the constraint + ** should be removed. */ + const char *zSpace = " "; + iEnd += getWhitespace(&zSql[iEnd]); + sqlite3GetToken(&zSql[iEnd], &t); + if( t==TK_RP || t==TK_COMMA ){ + zSpace = ""; + if( zSql[iStart-1]==',' ) iStart--; + } + + db = sqlite3_context_db_handle(ctx); + zNew = sqlite3MPrintf(db, "%.*s%s%s", iStart, zSql, zSpace, &zSql[iEnd]); + sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC); + } +} + +/* +** Internal SQL function: +** +** sqlite_add_constraint(SQL, CONSTRAINT-TEXT, ICOL) +** +** SQL is a CREATE TABLE statement. Return a modified version of +** SQL that adds CONSTRAINT-TEXT at the end of the ICOL-th column +** definition. (The left-most column defintion is 0.) +*/ +static void addConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = sqlite3_value_text(argv[0]); + const char *zCons = (const char*)sqlite3_value_text(argv[1]); + int iCol = sqlite3_value_int(argv[2]); + int iOff = 0; + int ii; + char *zNew = 0; + int t = 0; + sqlite3 *db; + UNUSED_PARAMETER(NotUsed); + + if( skipCreateTable(ctx, zSql, &iOff) ) return; + + for(ii=0; ii<=iCol || (iCol<0 && t!=TK_RP); ii++){ + iOff += getConstraintToken(&zSql[iOff], &t); + while( 1 ){ + int nTok = getConstraintToken(&zSql[iOff], &t); + if( t==TK_COMMA || t==TK_RP ) break; + if( t==TK_ILLEGAL ){ + sqlite3_result_error_code(ctx, SQLITE_CORRUPT_BKPT); + return; + } + iOff += nTok; + } + } + + iOff += getWhitespace(&zSql[iOff]); + + db = sqlite3_context_db_handle(ctx); + if( iCol<0 ){ + zNew = sqlite3MPrintf(db, "%.*s, %s%s", iOff, zSql, zCons, &zSql[iOff]); + }else{ + zNew = sqlite3MPrintf(db, "%.*s %s%s", iOff, zSql, zCons, &zSql[iOff]); + } + sqlite3_result_text(ctx, zNew, -1, SQLITE_DYNAMIC); +} + +/* +** Find a column named pCol in table pTab. If successful, set output +** parameter *piCol to the index of the column in the table and return +** SQLITE_OK. Otherwise, set *piCol to -1 and return an SQLite error +** code. +*/ +static int alterFindCol(Parse *pParse, Table *pTab, Token *pCol, int *piCol){ + sqlite3 *db = pParse->db; + char *zName = sqlite3NameFromToken(db, pCol); + int rc = SQLITE_NOMEM; + int iCol = -1; + + if( zName ){ + iCol = sqlite3ColumnIndex(pTab, zName); + if( iCol<0 ){ + sqlite3ErrorMsg(pParse, "no such column: %s", zName); + rc = SQLITE_ERROR; + }else{ + rc = SQLITE_OK; + } + } + +#ifndef SQLITE_OMIT_AUTHORIZATION + if( rc==SQLITE_OK ){ + const char *zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; + const char *zCol = pTab->aCol[iCol].zCnName; + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){ + pTab = 0; + } + } +#endif + + sqlite3DbFree(db, zName); + *piCol = iCol; + return rc; +} + + +/* +** Find the table named by the first entry in source list pSrc. If successful, +** return a pointer to the Table structure and set output variable (*pzDb) +** to point to the name of the database containin the table (i.e. "main", +** "temp" or the name of an attached database). +** +** If the table cannot be located, return NULL. The value of the two output +** parameters is undefined in this case. +*/ +static Table *alterFindTable( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Name of the table to look for */ + int *piDb, /* OUT: write the iDb here */ + const char **pzDb, /* OUT: write name of schema here */ + int bAuth /* Do ALTER TABLE authorization checks if true */ +){ + sqlite3 *db = pParse->db; + Table *pTab = 0; + assert( sqlite3BtreeHoldsAllMutexes(db) ); + pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]); + if( pTab ){ + int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + *pzDb = db->aDb[iDb].zDbSName; + *piDb = iDb; + + if( SQLITE_OK!=isRealTable(pParse, pTab, 2) + || SQLITE_OK!=isAlterableTable(pParse, pTab) + ){ + pTab = 0; + } + } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( pTab && bAuth ){ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, *pzDb, pTab->zName, 0) ){ + pTab = 0; + } + } +#endif + sqlite3SrcListDelete(db, pSrc); + return pTab; +} + +/* +** Generate bytecode for one of: +** +** (1) ALTER TABLE pSrc DROP CONSTRAINT pCons +** (2) ALTER TABLE pSrc ALTER pCol DROP NOT NULL +** +** One of pCons and pCol must be NULL and the other non-null. +*/ +SQLITE_PRIVATE void sqlite3AlterDropConstraint( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* The table being altered */ + Token *pCons, /* Name of the constraint to drop */ + Token *pCol /* Name of the column from which to remove the NOT NULL */ +){ + sqlite3 *db = pParse->db; + Table *pTab = 0; + int iDb = 0; + const char *zDb = 0; + char *zArg = 0; + + assert( (pCol==0)!=(pCons==0) ); + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, pCons!=0); + if( !pTab ) return; + + if( pCons ){ + zArg = sqlite3MPrintf(db, "%.*Q", pCons->n, pCons->z); + }else{ + int iCol; + if( alterFindCol(pParse, pTab, pCol, &iCol) ) return; + zArg = sqlite3MPrintf(db, "%d", iCol); + } + + /* Edit the SQL for the named table. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_drop_constraint(sql, %s) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, zArg, pTab->zName + ); + sqlite3DbFree(db, zArg); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + +/* +** The implementation of SQL function sqlite_fail(MSG). This takes a single +** argument, and returns it as an error message with the error code set to +** SQLITE_CONSTRAINT. +*/ +static void failConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const char *zText = (const char*)sqlite3_value_text(argv[0]); + int err = sqlite3_value_int(argv[1]); + (void)NotUsed; + sqlite3_result_error(ctx, zText, -1); + sqlite3_result_error_code(ctx, err); +} + +/* +** Buffer pCons, which is nCons bytes in size, contains the text of a +** NOT NULL or CHECK constraint that will be inserted into a CREATE TABLE +** statement. If successful, this function returns the size of the buffer in +** bytes not including any trailing whitespace or "--" style comments. Or, +** if an OOM occurs, it returns 0 and sets db->mallocFailed to true. +** +** C-style comments at the end are preserved. "--" style comments are +** removed because the comment terminator might be \000, and we are about +** to insert the pCons[] text into the middle of a larger string, and that +** will have the effect of removing the comment terminator and messing up +** the syntax. +*/ +static int alterRtrimConstraint( + sqlite3 *db, /* used to record OOM error */ + const char *pCons, /* Buffer containing constraint */ + int nCons /* Size of pCons in bytes */ +){ + u8 *zTmp = (u8*)sqlite3MPrintf(db, "%.*s", nCons, pCons); + int iOff = 0; + int iEnd = 0; + + if( zTmp==0 ) return 0; + + while( 1 ){ + int t = 0; + int nToken = sqlite3GetToken(&zTmp[iOff], &t); + if( t==TK_ILLEGAL ) break; + if( t!=TK_SPACE && (t!=TK_COMMENT || zTmp[iOff]!='-') ){ + iEnd = iOff+nToken; + } + iOff += nToken; + } + + sqlite3DbFree(db, zTmp); + return iEnd; +} + +/* +** Prepare a statement of the form: +** +** ALTER TABLE pSrc ALTER pCol SET NOT NULL +*/ +SQLITE_PRIVATE void sqlite3AlterSetNotNull( + Parse *pParse, /* Parsing context */ + SrcList *pSrc, /* Name of the table being altered */ + Token *pCol, /* Name of the column to add a NOT NULL constraint to */ + Token *pFirst /* The NOT token of the NOT NULL constraint text */ +){ + Table *pTab = 0; + int iCol = 0; + int iDb = 0; + const char *zDb = 0; + const char *pCons = 0; + int nCons = 0; + + /* Look up the table being altered. */ + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 0); + if( !pTab ) return; + + /* Find the column being altered. */ + if( alterFindCol(pParse, pTab, pCol, &iCol) ){ + return; + } + + /* Find the length in bytes of the constraint definition */ + pCons = pFirst->z; + nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons); + + /* Search for a constraint violation. Throw an exception if one is found. */ + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint failed', %d) " + "FROM %Q.%Q AS x WHERE x.%.*s IS NULL", + SQLITE_CONSTRAINT, zDb, pTab->zName, (int)pCol->n, pCol->z + ); + + /* Edit the SQL for the named table. */ + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_add_constraint(sqlite_drop_constraint(sql, %d), %.*Q, %d) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, iCol, nCons, pCons, iCol, pTab->zName + ); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + +/* +** Implementation of internal SQL function: +** +** sqlite_find_constraint(SQL, CONSTRAINT-NAME) +** +** This function returns true if the SQL passed as the first argument is a +** CREATE TABLE that contains a constraint with the name CONSTRAINT-NAME, +** or false otherwise. +*/ +static void findConstraintFunc( + sqlite3_context *ctx, + int NotUsed, + sqlite3_value **argv +){ + const u8 *zSql = 0; + const u8 *zCons = 0; + int iOff = 0; + int t = 0; + + (void)NotUsed; + zSql = sqlite3_value_text(argv[0]); + zCons = sqlite3_value_text(argv[1]); + + if( zSql==0 || zCons==0 ) return; + while( t!=TK_LP && t!=TK_ILLEGAL ){ + iOff += sqlite3GetToken(&zSql[iOff], &t); + } + + while( 1 ){ + iOff += getConstraintToken(&zSql[iOff], &t); + if( t==TK_CONSTRAINT ){ + int nTok = 0; + int cmp = 0; + iOff += getWhitespace(&zSql[iOff]); + nTok = getConstraintToken(&zSql[iOff], &t); + if( quotedCompare(ctx, t, &zSql[iOff], nTok, zCons, &cmp) ) return; + if( cmp==0 ){ + sqlite3_result_int(ctx, 1); + return; + } + }else if( t==TK_ILLEGAL ){ + break; + } + } + + sqlite3_result_int(ctx, 0); +} + +/* +** Generate bytecode to implement: +** +** ALTER TABLE pSrc ADD [CONSTRAINT pName] CHECK(pExpr) +** +** Any "ON CONFLICT" text that occurs after the "CHECK(...)", up +** until pParse->sLastToken, is included as part of the new constraint. +*/ +SQLITE_PRIVATE void sqlite3AlterAddConstraint( + Parse *pParse, /* Parse context */ + SrcList *pSrc, /* Table to add constraint to */ + Token *pFirst, /* First token of new constraint */ + Token *pName, /* Name of new constraint. NULL if name omitted. */ + const char *pExpr, /* Text of CHECK expression */ + int nExpr /* Size of pExpr in bytes */ +){ + Table *pTab = 0; /* Table identified by pSrc */ + int iDb = 0; /* Which schema does pTab live in */ + const char *zDb = 0; /* Name of the schema in which pTab lives */ + const char *pCons = 0; /* Text of the constraint */ + int nCons; /* Bytes of text to use from pCons[] */ + + /* Look up the table being altered. */ + assert( pSrc->nSrc==1 ); + pTab = alterFindTable(pParse, pSrc, &iDb, &zDb, 1); + if( !pTab ) return; + + /* If this new constraint has a name, check that it is not a duplicate of + ** an existing constraint. It is an error if it is. */ + if( pName ){ + char *zName = sqlite3NameFromToken(pParse->db, pName); + + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint %q already exists', %d) " + "FROM \"%w\"." LEGACY_SCHEMA_TABLE " " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase " + "AND sqlite_find_constraint(sql, %Q)", + zName, SQLITE_ERROR, zDb, pTab->zName, zName + ); + sqlite3DbFree(pParse->db, zName); + } + + /* Search for a constraint violation. Throw an exception if one is found. */ + sqlite3NestedParse(pParse, + "SELECT sqlite_fail('constraint failed', %d) " + "FROM %Q.%Q WHERE (%.*s) IS NOT TRUE", + SQLITE_CONSTRAINT, zDb, pTab->zName, nExpr, pExpr + ); + + /* Edit the SQL for the named table. */ + pCons = pFirst->z; + nCons = alterRtrimConstraint(pParse->db, pCons, pParse->sLastToken.z - pCons); + + sqlite3NestedParse(pParse, + "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET " + "sql = sqlite_add_constraint(sql, %.*Q, -1) " + "WHERE type='table' AND tbl_name=%Q COLLATE nocase" + , zDb, nCons, pCons, pTab->zName + ); + + /* Finally, reload the database schema. */ + renameReloadSchema(pParse, iDb, INITFLAG_AlterDropCons); +} + /* ** Register built-in functions used to help implement ALTER TABLE */ @@ -121433,6 +123370,10 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){ INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest), INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc), INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc), + INTERNAL_FUNCTION(sqlite_drop_constraint,2, dropConstraintFunc), + INTERNAL_FUNCTION(sqlite_fail, 2, failConstraintFunc), + INTERNAL_FUNCTION(sqlite_add_constraint, 3, addConstraintFunc), + INTERNAL_FUNCTION(sqlite_find_constraint,2, findConstraintFunc), }; sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs)); } @@ -124053,7 +125994,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep( if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) || sqlite3WalkExpr(&pFix->w, pStep->pWhere) || sqlite3WalkExprList(&pFix->w, pStep->pExprList) - || sqlite3FixSrcList(pFix, pStep->pFrom) + || sqlite3FixSrcList(pFix, pStep->pSrc) ){ return 1; } @@ -124160,7 +126101,7 @@ SQLITE_API int sqlite3_set_authorizer( sqlite3_mutex_enter(db->mutex); db->xAuth = (sqlite3_xauth)xAuth; db->pAuthArg = pArg; - if( db->xAuth ) sqlite3ExpirePreparedStatements(db, 1); + sqlite3ExpirePreparedStatements(db, 1); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -124831,6 +126772,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( const char *zDb; if( p->fg.fixedSchema ){ int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); + assert( iDb>=0 && iDbdb->nDb ); zDb = pParse->db->aDb[iDb].zDbSName; }else{ assert( !p->fg.isSubquery ); @@ -126404,8 +128346,8 @@ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){ ** The estimate is conservative. It might be larger that what is ** really needed. */ -static int identLength(const char *z){ - int n; +static i64 identLength(const char *z){ + i64 n; for(n=0; *z; n++, z++){ if( *z=='"' ){ n++; } } @@ -126838,9 +128780,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ if( !hasColumn(pPk->aiColumn, j, i) && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){ + const char *zColl = sqlite3ColumnColl(&pTab->aCol[i]); assert( jnColumn ); pPk->aiColumn[j] = i; - pPk->azColl[j] = sqlite3StrBINARY; + pPk->azColl[j] = zColl ? zColl : sqlite3StrBINARY; j++; } } @@ -126915,13 +128858,14 @@ SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){ ** restored to its original value prior to this routine returning. */ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ - char *zTail; /* Pointer to the last "_" in zName */ + const char *zTail; /* Pointer to the last "_" in zName */ Table *pTab; /* Table that zName is a shadow of */ + char *zCopy; zTail = strrchr(zName, '_'); if( zTail==0 ) return 0; - *zTail = 0; - pTab = sqlite3FindTable(db, zName, 0); - *zTail = '_'; + zCopy = sqlite3DbStrNDup(db, zName, (int)(zTail-zName)); + pTab = zCopy ? sqlite3FindTable(db, zCopy, 0) : 0; + sqlite3DbFree(db, zCopy); if( pTab==0 ) return 0; if( !IsVirtual(pTab) ) return 0; return sqlite3IsShadowTableOf(db, pTab, zName); @@ -127074,6 +129018,7 @@ SQLITE_PRIVATE void sqlite3EndTable( convertToWithoutRowidTable(pParse, p); } iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDb<=db->nDb ); #ifndef SQLITE_OMIT_CHECK /* Resolve names in all CHECK constraint expressions. @@ -127369,6 +129314,7 @@ SQLITE_PRIVATE void sqlite3CreateView( sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); + assert( iDb>=0 && iDbnDb ); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; @@ -128965,6 +130911,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists goto exit_drop_index; } iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); + assert( iDb>=0 && iDbnDb ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; @@ -129862,8 +131809,7 @@ SQLITE_PRIVATE void sqlite3RowidConstraint( } /* -** Check to see if pIndex uses the collating sequence pColl. Return -** true if it does and false if it does not. +** Return true if any column of pIndex uses the zColl collation */ #ifndef SQLITE_OMIT_REINDEX static int collationMatch(const char *zColl, Index *pIndex){ @@ -129871,8 +131817,8 @@ static int collationMatch(const char *zColl, Index *pIndex){ assert( zColl!=0 ); for(i=0; inColumn; i++){ const char *z = pIndex->azColl[i]; - assert( z!=0 || pIndex->aiColumn[i]<0 ); - if( pIndex->aiColumn[i]>=0 && 0==sqlite3StrICmp(z, zColl) ){ + assert( z!=0 ); + if( 0==sqlite3StrICmp(z, zColl) ){ return 1; } } @@ -129880,73 +131826,39 @@ static int collationMatch(const char *zColl, Index *pIndex){ } #endif -/* -** Recompute all indices of pTab that use the collating sequence pColl. -** If pColl==0 then recompute all indices of pTab. -*/ -#ifndef SQLITE_OMIT_REINDEX -static void reindexTable(Parse *pParse, Table *pTab, char const *zColl){ - if( !IsVirtual(pTab) ){ - Index *pIndex; /* An index associated with pTab */ - - for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ - if( zColl==0 || collationMatch(zColl, pIndex) ){ - int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); - } - } - } -} -#endif - -/* -** Recompute all indices of all tables in all databases where the -** indices use the collating sequence pColl. If pColl==0 then recompute -** all indices everywhere. -*/ -#ifndef SQLITE_OMIT_REINDEX -static void reindexDatabases(Parse *pParse, char const *zColl){ - Db *pDb; /* A single database */ - int iDb; /* The database index number */ - sqlite3 *db = pParse->db; /* The database connection */ - HashElem *k; /* For looping over tables in pDb */ - Table *pTab; /* A table in the database */ - - assert( sqlite3BtreeHoldsAllMutexes(db) ); /* Needed for schema access */ - for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ - assert( pDb!=0 ); - for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ - pTab = (Table*)sqliteHashData(k); - reindexTable(pParse, pTab, zColl); - } - } -} -#endif - /* ** Generate code for the REINDEX command. ** ** REINDEX -- 1 ** REINDEX -- 2 -** REINDEX ?.? -- 3 -** REINDEX ?.? -- 4 +** REINDEX ?.? -- 3 +** REINDEX ?.? -- 4 +** REINDEX EXPRESSIONS -- 5 ** -** Form 1 causes all indices in all attached databases to be rebuilt. -** Form 2 rebuilds all indices in all databases that use the named +** Form 1 causes all indexes in all attached databases to be rebuilt. +** Form 2 rebuilds all indexes in all databases that use the named ** collating function. Forms 3 and 4 rebuild the named index or all -** indices associated with the named table. +** indexes associated with the named table, respectively. Form 5 +** rebuilds all expression indexes in addition to all collations, +** indexes, or tables named "EXPRESSIONS". +** +** If the name is ambiguous such that it matches two or more of +** forms 2 through 5, then rebuild the union of all matching indexes, +** taken care to avoid rebuilding the same index more than once. */ #ifndef SQLITE_OMIT_REINDEX SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ - CollSeq *pColl; /* Collating sequence to be reindexed, or NULL */ - char *z; /* Name of a table or index */ - const char *zDb; /* Name of the database */ - Table *pTab; /* A table in the database */ - Index *pIndex; /* An index associated with pTab */ - int iDb; /* The database index number */ + char *z = 0; /* Name of a table or index or collation */ + const char *zDb = 0; /* Name of the database */ + int iReDb = -1; /* The database index number */ sqlite3 *db = pParse->db; /* The database connection */ Token *pObjName; /* Name of the table or index to be reindexed */ + int bMatch = 0; /* At least one name match */ + const char *zColl = 0; /* Rebuild indexes using this collation */ + Table *pReTab = 0; /* Rebuild all indexes of this table */ + Index *pReIndex = 0; /* Rebuild this index */ + int isExprIdx = 0; /* Rebuild all expression indexes */ + int bAll = 0; /* Rebuild all indexes */ /* Read the database schema. If an error occurs, leave an error message ** and code in pParse and return NULL. */ @@ -129955,41 +131867,66 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ } if( pName1==0 ){ - reindexDatabases(pParse, 0); - return; + /* rebuild all indexes */ + bMatch = 1; + bAll = 1; }else if( NEVER(pName2==0) || pName2->z==0 ){ - char *zColl; assert( pName1->z ); - zColl = sqlite3NameFromToken(pParse->db, pName1); - if( !zColl ) return; - pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); - if( pColl ){ - reindexDatabases(pParse, zColl); - sqlite3DbFree(db, zColl); - return; + z = sqlite3NameFromToken(pParse->db, pName1); + if( z==0 ) return; + }else{ + iReDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); + if( iReDb<0 ) return; + z = sqlite3NameFromToken(db, pObjName); + if( z==0 ) return; + zDb = db->aDb[iReDb].zDbSName; + } + if( !bAll ){ + if( zDb==0 && sqlite3StrICmp(z, "expressions")==0 ){ + isExprIdx = 1; + bMatch = 1; + } + if( zDb==0 && sqlite3FindCollSeq(db, ENC(db), z, 0)!=0 ){ + zColl = z; + bMatch = 1; + } + if( zColl==0 && (pReTab = sqlite3FindTable(db, z, zDb))!=0 ){ + bMatch = 1; + } + if( zColl==0 && (pReIndex = sqlite3FindIndex(db, z, zDb))!=0 ){ + bMatch = 1; } - sqlite3DbFree(db, zColl); } - iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName); - if( iDb<0 ) return; - z = sqlite3NameFromToken(db, pObjName); - if( z==0 ) return; - zDb = pName2->n ? db->aDb[iDb].zDbSName : 0; - pTab = sqlite3FindTable(db, z, zDb); - if( pTab ){ - reindexTable(pParse, pTab, 0); - sqlite3DbFree(db, z); - return; + if( bMatch ){ + int iDb; + HashElem *k; + Table *pTab; + Index *pIdx; + Db *pDb; + for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ + assert( pDb!=0 ); + if( iReDb>=0 && iReDb!=iDb ) continue; + for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ + pTab = (Table*)sqliteHashData(k); + if( IsVirtual(pTab) ) continue; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( bAll + || pTab==pReTab + || pIdx==pReIndex + || (isExprIdx && pIdx->bHasExpr) + || (zColl!=0 && collationMatch(zColl,pIdx)) + ){ + sqlite3BeginWriteOperation(pParse, 0, iDb); + sqlite3RefillIndex(pParse, pIdx, -1); + } + } /* End loop over indexes of pTab */ + } /* End loop over tables of iDb */ + } /* End loop over databases */ + }else{ + sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); } - pIndex = sqlite3FindIndex(db, z, zDb); sqlite3DbFree(db, z); - if( pIndex ){ - iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema); - sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3RefillIndex(pParse, pIndex, -1); - return; - } - sqlite3ErrorMsg(pParse, "unable to identify the object to be reindexed"); + return; } #endif @@ -130799,7 +132736,7 @@ static int vtabIsReadOnly(Parse *pParse, Table *pTab){ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS ** virtual tables if PRAGMA trusted_schema=ON. */ - if( pParse->pToplevel!=0 + if( (pParse->pToplevel!=0 || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && pTab->u.vtab.p->eVtabRisk > ((pParse->db->flags & SQLITE_TrustedSchema)!=0) ){ @@ -131636,8 +133573,9 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete( r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, - pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); - sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */ + pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn + ); + sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel); pPrior = pIdx; } @@ -132212,7 +134150,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3_result_error_nomem(context); return; } - sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); + sqlite3AtoF(zBuf, &r); sqlite3_free(zBuf); } sqlite3_result_double(context, r); @@ -132844,18 +134782,11 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int switch( sqlite3_value_type(pValue) ){ case SQLITE_FLOAT: { - double r1, r2; - const char *zVal; - r1 = sqlite3_value_double(pValue); - sqlite3_str_appendf(pStr, "%!0.15g", r1); - zVal = sqlite3_str_value(pStr); - if( zVal ){ - sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8); - if( r1!=r2 ){ - sqlite3_str_reset(pStr); - sqlite3_str_appendf(pStr, "%!0.20e", r1); - } - } + /* ,--- Show infinity as 9.0e+999 + ** | + ** | ,--- 17 precision guarantees round-trip + ** v v */ + sqlite3_str_appendf(pStr, "%!0.17g", sqlite3_value_double(pValue)); break; } case SQLITE_INTEGER: { @@ -132947,7 +134878,7 @@ static void unistrFunc( } i = j = 0; while( ifuncFlags |= flags; pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE; } @@ -135898,6 +137831,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ if( p ){ TriggerStep *pStep = p->step_list; + sqlite3SrcListDelete(dbMem, pStep->pSrc); sqlite3ExprDelete(dbMem, pStep->pWhere); sqlite3ExprListDelete(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); @@ -136117,6 +138051,7 @@ SQLITE_PRIVATE void sqlite3FkCheck( if( !IsOrdinaryTable(pTab) ) return; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDb>=00 && iDbnDb ); zDb = db->aDb[iDb].zDbSName; /* Loop through all the foreign key constraints for which pTab is the @@ -136534,7 +138469,6 @@ static Trigger *fkActionTrigger( nFrom = sqlite3Strlen30(zFrom); if( action==OE_Restrict ){ - int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); SrcList *pSrc; Expr *pRaise; @@ -136545,10 +138479,10 @@ static Trigger *fkActionTrigger( } pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ - assert( pSrc->nSrc==1 ); - pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); - assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 ); - pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); + SrcItem *pItem = &pSrc->a[0]; + pItem->zName = sqlite3DbStrDup(db, zFrom); + pItem->fg.fixedSchema = 1; + pItem->u4.pSchema = pTab->pSchema; } pSelect = sqlite3SelectNew(pParse, sqlite3ExprListAppend(pParse, 0, pRaise), @@ -136564,14 +138498,17 @@ static Trigger *fkActionTrigger( pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ - sizeof(TriggerStep) + /* Single step in trigger program */ - nFrom + 1 /* Space for pStep->zTarget */ + sizeof(TriggerStep) /* Single step in trigger program */ ); if( pTrigger ){ pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; - pStep->zTarget = (char *)&pStep[1]; - memcpy((char *)pStep->zTarget, zFrom, nFrom); - + pStep->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); + if( pStep->pSrc ){ + SrcItem *pItem = &pStep->pSrc->a[0]; + pItem->zName = sqlite3DbStrNDup(db, zFrom, nFrom); + pItem->u4.pSchema = pTab->pSchema; + pItem->fg.fixedSchema = 1; + } pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); @@ -140628,7 +142565,11 @@ struct sqlite3_api_routines { /* Version 3.51.0 and later */ int (*set_errmsg)(sqlite3*,int,const char*); int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int); - + /* Version 3.52.0 and later */ + void (*str_truncate)(sqlite3_str*,int); + void (*str_free)(sqlite3_str*); + int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*)); + int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*); }; /* @@ -140967,6 +142908,11 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.51.0 and later */ #define sqlite3_set_errmsg sqlite3_api->set_errmsg #define sqlite3_db_status64 sqlite3_api->db_status64 +/* Version 3.52.0 and later */ +#define sqlite3_str_truncate sqlite3_api->str_truncate +#define sqlite3_str_free sqlite3_api->str_free +#define sqlite3_carray_bind sqlite3_api->carray_bind +#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2 #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) @@ -141493,7 +143439,17 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_setlk_timeout, /* Version 3.51.0 and later */ sqlite3_set_errmsg, - sqlite3_db_status64 + sqlite3_db_status64, + /* Version 3.52.0 and later */ + sqlite3_str_truncate, + sqlite3_str_free, +#ifdef SQLITE_ENABLE_CARRAY + sqlite3_carray_bind, + sqlite3_carray_bind_v2 +#else + 0, + 0 +#endif }; /* True if x is the directory separator character @@ -141595,33 +143551,42 @@ static int sqlite3LoadExtension( ** entry point name "sqlite3_extension_init" was not found, then ** construct an entry point name "sqlite3_X_init" where the X is ** replaced by the lowercase value of every ASCII alphabetic - ** character in the filename after the last "/" upto the first ".", - ** and eliding the first three characters if they are "lib". + ** character in the filename after the last "/" up to the first ".", + ** and skipping the first three characters if they are "lib". ** Examples: ** ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init ** C:/lib/mathfuncs.dll ==> sqlite3_mathfuncs_init + ** + ** If that still finds no entry point, repeat a second time but this + ** time include both alphabetic and numeric characters up to the first + ** ".". Example: + ** + ** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example5_init */ if( xInit==0 && zProc==0 ){ int iFile, iEntry, c; int ncFile = sqlite3Strlen30(zFile); + int cnt = 0; zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } - memcpy(zAltEntry, "sqlite3_", 8); - for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} - iFile++; - if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; - for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ - if( sqlite3Isalpha(c) ){ - zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; + do{ + memcpy(zAltEntry, "sqlite3_", 8); + for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){} + iFile++; + if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3; + for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){ + if( sqlite3Isalpha(c) || (cnt && sqlite3Isdigit(c)) ){ + zAltEntry[iEntry++] = (char)sqlite3UpperToLower[(unsigned)c]; + } } - } - memcpy(zAltEntry+iEntry, "_init", 6); - zEntry = zAltEntry; - xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); + memcpy(zAltEntry+iEntry, "_init", 6); + zEntry = zAltEntry; + xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry); + }while( xInit==0 && (++cnt)<2 ); } if( xInit==0 ){ if( pzErrMsg ){ @@ -144631,8 +146596,20 @@ SQLITE_PRIVATE void sqlite3Pragma( pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);/* increment entry count */ /* Verify that an index entry exists for the current table row */ - jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, + sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1, pIdx->nColumn); VdbeCoverage(v); + jmp2 = sqlite3VdbeAddOp3(v, OP_IFindKey, iIdxCur+j, ckUniq, r1); + VdbeCoverage(v); + sqlite3VdbeChangeP4(v, -1, (const char*)pIdx, P4_INDEX); + sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, + sqlite3MPrintf(db, "index %s stores an imprecise floating-point " + "value for row ", pIdx->zName), + P4_DYNAMIC); + sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); + integrityCheckResultRow(v); + sqlite3VdbeAddOp2(v, OP_Goto, 0, ckUniq); + + sqlite3VdbeJumpHere(v, jmp2); sqlite3VdbeLoadString(v, 3, "row "); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeLoadString(v, 4, " missing from index "); @@ -144640,7 +146617,7 @@ SQLITE_PRIVATE void sqlite3Pragma( jmp5 = sqlite3VdbeLoadString(v, 4, pIdx->zName); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); jmp4 = integrityCheckResultRow(v); - sqlite3VdbeJumpHere(v, jmp2); + sqlite3VdbeResolveLabel(v, ckUniq); /* The OP_IdxRowid opcode is an optimized version of OP_Column ** that extracts the rowid off the end of the index record. @@ -145693,7 +147670,8 @@ static void corruptSchema( static const char *azAlterType[] = { "rename", "drop column", - "add column" + "add column", + "drop constraint" }; *pData->pzErrMsg = sqlite3MPrintf(db, "error in %s %s after %s: %s", azObj[0], azObj[1], @@ -146776,7 +148754,7 @@ SQLITE_API int sqlite3_prepare16_v3( */ typedef struct DistinctCtx DistinctCtx; struct DistinctCtx { - u8 isTnct; /* 0: Not distinct. 1: DISTICT 2: DISTINCT and ORDER BY */ + u8 isTnct; /* 0: Not distinct. 1: DISTINCT 2: DISTINCT and ORDER BY */ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ int tabTnct; /* Ephemeral table used for DISTINCT processing */ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ @@ -146906,8 +148884,6 @@ SQLITE_PRIVATE Select *sqlite3SelectNew( pNew->iLimit = 0; pNew->iOffset = 0; pNew->selId = ++pParse->nSelect; - pNew->addrOpenEphm[0] = -1; - pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); pNew->pSrc = pSrc; @@ -147416,6 +149392,10 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ pRight->fg.isOn = 1; p->selFlags |= SF_OnToWhere; } + + if( IsVirtual(pRightTab) && joinType==EP_OuterON && pRight->u1.pFuncArg ){ + p->selFlags |= SF_OnToWhere; + } } return 0; } @@ -148055,29 +150035,6 @@ static void selectInnerLoop( } switch( eDest ){ - /* In this mode, write each query result to the key of the temporary - ** table iParm. - */ -#ifndef SQLITE_OMIT_COMPOUND_SELECT - case SRT_Union: { - int r1; - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); - sqlite3ReleaseTempReg(pParse, r1); - break; - } - - /* Construct a record from the query result, but instead of - ** saving that record, use it as a key to delete elements from - ** the temporary table iParm. - */ - case SRT_Except: { - sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nResultCol); - break; - } -#endif /* SQLITE_OMIT_COMPOUND_SELECT */ - /* Store the result as data using a unique key. */ case SRT_Fifo: @@ -149190,8 +151147,8 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes( } } if( zType ){ - const i64 k = sqlite3Strlen30(zType); - n = sqlite3Strlen30(pCol->zCnName); + const i64 k = strlen(zType); + n = strlen(pCol->zCnName); pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+k+2); pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); if( pCol->zCnName ){ @@ -149364,9 +151321,9 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ ** function is responsible for ensuring that this structure is eventually ** freed. */ -static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){ +static KeyInfo *multiSelectByMergeKeyInfo(Parse *pParse, Select *p, int nExtra){ ExprList *pOrderBy = p->pOrderBy; - int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0; + int nOrderBy = (pOrderBy!=0) ? pOrderBy->nExpr : 0; sqlite3 *db = pParse->db; KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1); if( pRet ){ @@ -149499,7 +151456,7 @@ static void generateWithRecursiveQuery( regCurrent = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol); if( pOrderBy ){ - KeyInfo *pKeyInfo = multiSelectOrderByKeyInfo(pParse, p, 1); + KeyInfo *pKeyInfo = multiSelectByMergeKeyInfo(pParse, p, 1); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iQueue, pOrderBy->nExpr+2, 0, (char*)pKeyInfo, P4_KEYINFO); destQueue.pOrderBy = pOrderBy; @@ -149508,8 +151465,28 @@ static void generateWithRecursiveQuery( } VdbeComment((v, "Queue table")); if( iDistinct ){ - p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0); - p->selFlags |= SF_UsesEphemeral; + /* Generate an ephemeral table used to enforce distinctness on the + ** output of the recursive part of the CTE. + */ + KeyInfo *pKeyInfo; /* Collating sequence for the result set */ + CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ + + assert( p->pNext==0 ); + assert( p->pEList!=0 ); + nCol = p->pEList->nExpr; + pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nCol, 1); + if( pKeyInfo ){ + for(i=0, apColl=pKeyInfo->aColl; idb->pDfltColl; + } + } + sqlite3VdbeAddOp4(v, OP_OpenEphemeral, iDistinct, nCol, 0, + (void*)pKeyInfo, P4_KEYINFO); + }else{ + assert( pParse->nErr>0 ); + } } /* Detach the ORDER BY clause from the compound SELECT */ @@ -149584,7 +151561,7 @@ end_of_recursive_query: #endif /* SQLITE_OMIT_CTE */ /* Forward references */ -static int multiSelectOrderBy( +static int multiSelectByMerge( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ @@ -149733,12 +151710,26 @@ static int multiSelect( generateWithRecursiveQuery(pParse, p, &dest); }else #endif - - /* Compound SELECTs that have an ORDER BY clause are handled separately. - */ if( p->pOrderBy ){ - return multiSelectOrderBy(pParse, p, pDest); + /* If the compound has an ORDER BY clause, then always use the merge + ** algorithm. */ + return multiSelectByMerge(pParse, p, pDest); + }else if( p->op!=TK_ALL ){ + /* If the compound is EXCEPT, INTERSECT, or UNION (anything other than + ** UNION ALL) then also always use the merge algorithm. However, the + ** multiSelectByMerge() routine requires that the compound have an + ** ORDER BY clause, and it doesn't right now. So invent one first. */ + Expr *pOne = sqlite3ExprInt32(db, 1); + p->pOrderBy = sqlite3ExprListAppend(pParse, 0, pOne); + if( pParse->nErr ) goto multi_select_end; + assert( p->pOrderBy!=0 ); + p->pOrderBy->a[0].u.x.iOrderByCol = 1; + return multiSelectByMerge(pParse, p, pDest); }else{ + /* For a UNION ALL compound without ORDER BY, simply run the left + ** query, then run the right query */ + int addr = 0; + int nLimit = 0; /* Initialize to suppress harmless compiler warning */ #ifndef SQLITE_OMIT_EXPLAIN if( pPrior->pPrior==0 ){ @@ -149746,300 +151737,49 @@ static int multiSelect( ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); } #endif - - /* Generate code for the left and right SELECT statements. - */ - switch( p->op ){ - case TK_ALL: { - int addr = 0; - int nLimit = 0; /* Initialize to suppress harmless compiler warning */ - assert( !pPrior->pLimit ); - pPrior->iLimit = p->iLimit; - pPrior->iOffset = p->iOffset; - pPrior->pLimit = p->pLimit; - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); - rc = sqlite3Select(pParse, pPrior, &dest); - pPrior->pLimit = 0; - if( rc ){ - goto multi_select_end; - } - p->pPrior = 0; - p->iLimit = pPrior->iLimit; - p->iOffset = pPrior->iOffset; - if( p->iLimit ){ - addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); - VdbeComment((v, "Jump ahead if LIMIT reached")); - if( p->iOffset ){ - sqlite3VdbeAddOp3(v, OP_OffsetLimit, - p->iLimit, p->iOffset+1, p->iOffset); - } - } - ExplainQueryPlan((pParse, 1, "UNION ALL")); - TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); - rc = sqlite3Select(pParse, p, &dest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - if( p->pLimit - && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse) - && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) - ){ - p->nSelectRow = sqlite3LogEst((u64)nLimit); - } - if( addr ){ - sqlite3VdbeJumpHere(v, addr); - } - break; - } - case TK_EXCEPT: - case TK_UNION: { - int unionTab; /* Cursor number of the temp table holding result */ - u8 op = 0; /* One of the SRT_ operations to apply to self */ - int priorOp; /* The SRT_ operation to apply to prior selects */ - Expr *pLimit; /* Saved values of p->nLimit */ - int addr; - int emptyBypass = 0; /* IfEmpty opcode to bypass RHS */ - SelectDest uniondest; - - - testcase( p->op==TK_EXCEPT ); - testcase( p->op==TK_UNION ); - priorOp = SRT_Union; - if( dest.eDest==priorOp ){ - /* We can reuse a temporary table generated by a SELECT to our - ** right. - */ - assert( p->pLimit==0 ); /* Not allowed on leftward elements */ - unionTab = dest.iSDParm; - }else{ - /* We will need to create our own temporary table to hold the - ** intermediate results. - */ - unionTab = pParse->nTab++; - assert( p->pOrderBy==0 ); - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - } - - - /* Code the SELECT statements to our left - */ - assert( !pPrior->pOrderBy ); - sqlite3SelectDestInit(&uniondest, priorOp, unionTab); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n")); - rc = sqlite3Select(pParse, pPrior, &uniondest); - if( rc ){ - goto multi_select_end; - } - - /* Code the current SELECT statement - */ - if( p->op==TK_EXCEPT ){ - op = SRT_Except; - emptyBypass = sqlite3VdbeAddOp1(v, OP_IfEmpty, unionTab); - VdbeCoverage(v); - }else{ - assert( p->op==TK_UNION ); - op = SRT_Union; - } - p->pPrior = 0; - pLimit = p->pLimit; - p->pLimit = 0; - uniondest.eDest = op; - ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", - sqlite3SelectOpName(p->op))); - TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n")); - rc = sqlite3Select(pParse, p, &uniondest); - testcase( rc!=SQLITE_OK ); - assert( p->pOrderBy==0 ); - pDelete = p->pPrior; - p->pPrior = pPrior; - p->pOrderBy = 0; - if( p->op==TK_UNION ){ - p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); - } - if( emptyBypass ) sqlite3VdbeJumpHere(v, emptyBypass); - sqlite3ExprDelete(db, p->pLimit); - p->pLimit = pLimit; - p->iLimit = 0; - p->iOffset = 0; - - /* Convert the data in the temporary table into whatever form - ** it is that we currently need. - */ - assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); - assert( p->pEList || db->mallocFailed ); - if( dest.eDest!=priorOp && db->mallocFailed==0 ){ - int iCont, iBreak, iStart; - iBreak = sqlite3VdbeMakeLabel(pParse); - iCont = sqlite3VdbeMakeLabel(pParse); - computeLimitRegisters(pParse, p, iBreak); - sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); - iStart = sqlite3VdbeCurrentAddr(v); - selectInnerLoop(pParse, p, unionTab, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); - } - break; - } - default: assert( p->op==TK_INTERSECT ); { - int tab1, tab2; - int iCont, iBreak, iStart; - Expr *pLimit; - int addr, iLimit, iOffset; - SelectDest intersectdest; - int r1; - int emptyBypass; - - /* INTERSECT is different from the others since it requires - ** two temporary tables. Hence it has its own case. Begin - ** by allocating the tables we will need. - */ - tab1 = pParse->nTab++; - tab2 = pParse->nTab++; - assert( p->pOrderBy==0 ); - - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); - assert( p->addrOpenEphm[0] == -1 ); - p->addrOpenEphm[0] = addr; - findRightmost(p)->selFlags |= SF_UsesEphemeral; - assert( p->pEList ); - - /* Code the SELECTs to our left into temporary table "tab1". - */ - sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n")); - rc = sqlite3Select(pParse, pPrior, &intersectdest); - if( rc ){ - goto multi_select_end; - } - - /* Initialize LIMIT counters before checking to see if the LHS - ** is empty, in case the jump is taken */ - iBreak = sqlite3VdbeMakeLabel(pParse); - computeLimitRegisters(pParse, p, iBreak); - emptyBypass = sqlite3VdbeAddOp1(v, OP_IfEmpty, tab1); VdbeCoverage(v); - - /* Code the current SELECT into temporary table "tab2" - */ - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); - assert( p->addrOpenEphm[1] == -1 ); - p->addrOpenEphm[1] = addr; - - /* Disable prior SELECTs and the LIMIT counters during the computation - ** of the RHS select */ - pLimit = p->pLimit; - iLimit = p->iLimit; - iOffset = p->iOffset; - p->pPrior = 0; - p->pLimit = 0; - p->iLimit = 0; - p->iOffset = 0; - - intersectdest.iSDParm = tab2; - ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", - sqlite3SelectOpName(p->op))); - TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n")); - rc = sqlite3Select(pParse, p, &intersectdest); - testcase( rc!=SQLITE_OK ); - pDelete = p->pPrior; - p->pPrior = pPrior; - if( p->nSelectRow>pPrior->nSelectRow ){ - p->nSelectRow = pPrior->nSelectRow; - } - sqlite3ExprDelete(db, p->pLimit); - - /* Reinstate the LIMIT counters prior to running the final intersect */ - p->pLimit = pLimit; - p->iLimit = iLimit; - p->iOffset = iOffset; - - /* Generate code to take the intersection of the two temporary - ** tables. - */ - if( rc ) break; - assert( p->pEList ); - sqlite3VdbeAddOp1(v, OP_Rewind, tab1); - r1 = sqlite3GetTempReg(pParse); - iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); - iCont = sqlite3VdbeMakeLabel(pParse); - sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); - VdbeCoverage(v); - sqlite3ReleaseTempReg(pParse, r1); - selectInnerLoop(pParse, p, tab1, - 0, 0, &dest, iCont, iBreak); - sqlite3VdbeResolveLabel(v, iCont); - sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); - sqlite3VdbeResolveLabel(v, iBreak); - sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); - sqlite3VdbeJumpHere(v, emptyBypass); - sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); - break; + assert( !pPrior->pLimit ); + pPrior->iLimit = p->iLimit; + pPrior->iOffset = p->iOffset; + pPrior->pLimit = sqlite3ExprDup(db, p->pLimit, 0); + TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n")); + rc = sqlite3Select(pParse, pPrior, &dest); + sqlite3ExprDelete(db, pPrior->pLimit); + pPrior->pLimit = 0; + if( rc ){ + goto multi_select_end; + } + p->pPrior = 0; + p->iLimit = pPrior->iLimit; + p->iOffset = pPrior->iOffset; + if( p->iLimit ){ + addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); + VdbeComment((v, "Jump ahead if LIMIT reached")); + if( p->iOffset ){ + sqlite3VdbeAddOp3(v, OP_OffsetLimit, + p->iLimit, p->iOffset+1, p->iOffset); } } - - #ifndef SQLITE_OMIT_EXPLAIN + ExplainQueryPlan((pParse, 1, "UNION ALL")); + TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n")); + rc = sqlite3Select(pParse, p, &dest); + testcase( rc!=SQLITE_OK ); + pDelete = p->pPrior; + p->pPrior = pPrior; + p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); + if( p->pLimit + && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit, pParse) + && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) + ){ + p->nSelectRow = sqlite3LogEst((u64)nLimit); + } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } +#ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } - #endif - } - if( pParse->nErr ) goto multi_select_end; - - /* Compute collating sequences used by - ** temporary tables needed to implement the compound select. - ** Attach the KeyInfo structure to all temporary tables. - ** - ** This section is run by the right-most SELECT statement only. - ** SELECT statements to the left always skip this part. The right-most - ** SELECT might also skip this part if it has no ORDER BY clause and - ** no temp tables are required. - */ - if( p->selFlags & SF_UsesEphemeral ){ - int i; /* Loop counter */ - KeyInfo *pKeyInfo; /* Collating sequence for the result set */ - Select *pLoop; /* For looping through SELECT statements */ - CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ - int nCol; /* Number of columns in result set */ - - assert( p->pNext==0 ); - assert( p->pEList!=0 ); - nCol = p->pEList->nExpr; - pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1); - if( !pKeyInfo ){ - rc = SQLITE_NOMEM_BKPT; - goto multi_select_end; - } - for(i=0, apColl=pKeyInfo->aColl; ipDfltColl; - } - } - - for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ - for(i=0; i<2; i++){ - int addr = pLoop->addrOpenEphm[i]; - if( addr<0 ){ - /* If [0] is unused then [1] is also unused. So we can - ** always safely abort as soon as the first unused slot is found */ - assert( pLoop->addrOpenEphm[1]<0 ); - break; - } - sqlite3VdbeChangeP2(v, addr, nCol); - sqlite3VdbeChangeP4(v, addr, (char*)sqlite3KeyInfoRef(pKeyInfo), - P4_KEYINFO); - pLoop->addrOpenEphm[i] = -1; - } - } - sqlite3KeyInfoUnref(pKeyInfo); +#endif } multi_select_end: @@ -150071,8 +151811,8 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){ ** Code an output subroutine for a coroutine implementation of a ** SELECT statement. ** -** The data to be output is contained in pIn->iSdst. There are -** pIn->nSdst columns to be output. pDest is where the output should +** The data to be output is contained in an array of pIn->nSdst registers +** starting at register pIn->iSdst. pDest is where the output should ** be sent. ** ** regReturn is the number of the register holding the subroutine @@ -150101,6 +151841,8 @@ static int generateOutputSubroutine( int iContinue; int addr; + assert( pIn->eDest==SRT_Coroutine ); + addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(pParse); @@ -150122,23 +151864,60 @@ static int generateOutputSubroutine( */ codeOffset(v, p->iOffset, iContinue); - assert( pDest->eDest!=SRT_Exists ); - assert( pDest->eDest!=SRT_Table ); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ + case SRT_Fifo: + case SRT_DistFifo: + case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); + int iParm = pDest->iSDParm; + testcase( pDest->eDest==SRT_Table ); + testcase( pDest->eDest==SRT_EphemTab ); + testcase( pDest->eDest==SRT_Fifo ); + testcase( pDest->eDest==SRT_DistFifo ); sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r1); - sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iSDParm, r2); - sqlite3VdbeAddOp3(v, OP_Insert, pDest->iSDParm, r1, r2); +#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG) + /* A destination of SRT_Table and a non-zero iSDParm2 parameter means + ** that this is an "UPDATE ... FROM" on a virtual table or view. In this + ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC. + ** This does not affect operation in any way - it just allows MakeRecord + ** to process OPFLAG_NOCHANGE values without an assert() failing. */ + if( pDest->eDest==SRT_Table && pDest->iSDParm2 ){ + sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); + } +#endif +#ifndef SQLITE_OMIT_CTE + if( pDest->eDest==SRT_DistFifo ){ + /* If the destination is DistFifo, then cursor (iParm+1) is open + ** on an ephemeral index that is used to enforce uniqueness on the + ** total result. At this point, we are processing the setup portion + ** of the recursive CTE using the merge algorithm, so the results are + ** guaranteed to be unique anyhow. But we still need to populate the + ** (iParm+1) cursor for use by the subsequent recursive phase. + */ + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1, + pIn->iSdst, pIn->nSdst); + } +#endif + sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); + sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); sqlite3ReleaseTempReg(pParse, r1); break; } + /* If any row exist in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iSDParm); + /* The LIMIT clause will terminate the loop for us */ + break; + } + #ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)". */ @@ -150185,9 +151964,51 @@ static int generateOutputSubroutine( break; } +#ifndef SQLITE_OMIT_CTE + /* Write the results into a priority queue that is order according to + ** pDest->pOrderBy (in pSO). pDest->iSDParm (in iParm) is the cursor for an + ** index with pSO->nExpr+2 columns. Build a key using pSO for the first + ** pSO->nExpr columns, then make sure all keys are unique by adding a + ** final OP_Sequence column. The last column is the record as a blob. + */ + case SRT_DistQueue: + case SRT_Queue: { + int nKey; + int r1, r2, r3, ii; + ExprList *pSO; + int iParm = pDest->iSDParm; + pSO = pDest->pOrderBy; + assert( pSO ); + nKey = pSO->nExpr; + r1 = sqlite3GetTempReg(pParse); + r2 = sqlite3GetTempRange(pParse, nKey+2); + r3 = r2+nKey+1; + + sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst, r3); + if( pDest->eDest==SRT_DistQueue ){ + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r3); + } + for(ii=0; iiiSdst + pSO->a[ii].u.x.iOrderByCol - 1, + r2+ii); + } + sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey); + sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2); + sqlite3ReleaseTempReg(pParse, r1); + sqlite3ReleaseTempRange(pParse, r2, nKey+2); + break; + } +#endif /* SQLITE_OMIT_CTE */ + + /* Ignore the output */ + case SRT_Discard: { + break; + } + /* If none of the above, then the result destination must be - ** SRT_Output. This routine is never called with any other - ** destination other than the ones handled above or SRT_Output. + ** SRT_Output. ** ** For SRT_Output, results are stored in a sequence of registers. ** Then the OP_ResultRow opcode is used to cause sqlite3_step() to @@ -150215,8 +152036,9 @@ static int generateOutputSubroutine( } /* -** Alternative compound select code generator for cases when there -** is an ORDER BY clause. +** Generate code for a compound SELECT statement using a merge +** algorithm. The compound must have an ORDER BY clause for this +** to work. ** ** We assume a query of the following form: ** @@ -150233,7 +152055,7 @@ static int generateOutputSubroutine( ** ** outB: Move the output of the selectB coroutine into the output ** of the compound query. (Only generated for UNION and -** UNION ALL. EXCEPT and INSERTSECT never output a row that +** UNION ALL. EXCEPT and INTERSECT never output a row that ** appears only in B.) ** ** AltB: Called when there is data from both coroutines and Au.x.iOrderByCol==i ) break; } if( j==nOrderBy ){ - Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pNew = sqlite3ExprInt32(db, i); if( pNew==0 ) return SQLITE_NOMEM_BKPT; - pNew->flags |= EP_IntValue; - pNew->u.iValue = i; p->pOrderBy = pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew); if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i; } @@ -150383,26 +152201,29 @@ static int multiSelectOrderBy( } /* Compute the comparison permutation and keyinfo that is used with - ** the permutation used to determine if the next - ** row of results comes from selectA or selectB. Also add explicit - ** collations to the ORDER BY clause terms so that when the subqueries - ** to the right and the left are evaluated, they use the correct - ** collation. + ** the permutation to determine if the next row of results comes + ** from selectA or selectB. Also add literal collations to the + ** ORDER BY clause terms so that when selectA and selectB are + ** evaluated, they use the correct collation. */ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; + int bKeep = 0; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ assert( pItem!=0 ); assert( pItem->u.x.iOrderByCol>0 ); assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->u.x.iOrderByCol - 1; + if( aPermute[i]!=(u32)i-1 ) bKeep = 1; + } + if( bKeep==0 ){ + sqlite3DbFreeNN(db, aPermute); + aPermute = 0; } - pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1); - }else{ - pKeyMerge = 0; } + pKeyMerge = multiSelectByMergeKeyInfo(pParse, p, 1); /* Allocate a range of temporary registers and the KeyInfo needed ** for the logic that removes duplicate result rows when the @@ -150481,7 +152302,7 @@ static int multiSelectOrderBy( */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); - VdbeComment((v, "left SELECT")); + VdbeComment((v, "SUBR: next-A")); pPrior->iLimit = regLimitA; ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); @@ -150493,7 +152314,7 @@ static int multiSelectOrderBy( */ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); - VdbeComment((v, "right SELECT")); + VdbeComment((v, "SUBR: next-B")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; @@ -150507,7 +152328,7 @@ static int multiSelectOrderBy( /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. */ - VdbeNoopComment((v, "Output routine for A")); + VdbeNoopComment((v, "SUBR: out-A")); addrOutA = generateOutputSubroutine(pParse, p, &destA, pDest, regOutA, regPrev, pKeyDup, labelEnd); @@ -150516,7 +152337,7 @@ static int multiSelectOrderBy( ** select as the next output row of the compound select. */ if( op==TK_ALL || op==TK_UNION ){ - VdbeNoopComment((v, "Output routine for B")); + VdbeNoopComment((v, "SUBR: out-B")); addrOutB = generateOutputSubroutine(pParse, p, &destB, pDest, regOutB, regPrev, pKeyDup, labelEnd); @@ -150529,10 +152350,12 @@ static int multiSelectOrderBy( if( op==TK_EXCEPT || op==TK_INTERSECT ){ addrEofA_noB = addrEofA = labelEnd; }else{ - VdbeNoopComment((v, "eof-A subroutine")); + VdbeNoopComment((v, "SUBR: eof-A")); addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + VdbeComment((v, "out-B")); addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd); VdbeCoverage(v); + VdbeComment((v, "next-B")); sqlite3VdbeGoto(v, addrEofA); p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } @@ -150544,17 +152367,20 @@ static int multiSelectOrderBy( addrEofB = addrEofA; if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; }else{ - VdbeNoopComment((v, "eof-B subroutine")); + VdbeNoopComment((v, "SUBR: eof-B")); addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA); + VdbeComment((v, "out-A")); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v); + VdbeComment((v, "next-A")); sqlite3VdbeGoto(v, addrEofB); } /* Generate code to handle the case of AB */ - VdbeNoopComment((v, "A-gt-B subroutine")); addrAgtB = sqlite3VdbeCurrentAddr(v); if( op==TK_ALL || op==TK_UNION ){ sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB); + VdbeComment((v, "out-B")); + sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + VdbeComment((v, "next-B")); + sqlite3VdbeGoto(v, labelCmpr); + }else{ + addrAgtB++; /* Just do next-B. Might as well use the next-B call + ** in the next code block */ } - sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); - sqlite3VdbeGoto(v, labelCmpr); /* This code runs once to initialize everything. */ sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB); VdbeCoverage(v); + VdbeComment((v, "next-A")); + /* v--- Also the A>B case for EXCEPT and INTERSECT */ sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB); VdbeCoverage(v); + VdbeComment((v, "next-B")); /* Implement the main merge loop */ + if( aPermute!=0 ){ + sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); + } sqlite3VdbeResolveLabel(v, labelCmpr); - sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO); - sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); - sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); + if( aPermute!=0 ){ + sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); + } + sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); + VdbeCoverageIf(v, op==TK_ALL); + VdbeCoverageIf(v, op==TK_UNION); + VdbeCoverageIf(v, op==TK_EXCEPT); + VdbeCoverageIf(v, op==TK_INTERSECT); /* Jump to the this point in order to terminate the query. */ @@ -151511,7 +153349,7 @@ static int flattenSubquery( } pSubitem->fg.jointype |= jointype; - /* Now begin substituting subquery result set expressions for + /* Begin substituting subquery result set expressions for ** references to the iParent in the outer query. ** ** Example: @@ -151523,7 +153361,7 @@ static int flattenSubquery( ** We look at every expression in the outer query and every place we see ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10". */ - if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){ + if( pSub->pOrderBy ){ /* At this point, any non-zero iOrderByCol values indicate that the ** ORDER BY column expression is identical to the iOrderByCol'th ** expression returned by SELECT statement pSub. Since these values @@ -151531,9 +153369,9 @@ static int flattenSubquery( ** zero them before transferring the ORDER BY clause. ** ** Not doing this may cause an error if a subsequent call to this - ** function attempts to flatten a compound sub-query into pParent - ** (the only way this can happen is if the compound sub-query is - ** currently part of pSub->pSrc). See ticket [d11a6e908f]. */ + ** function attempts to flatten a compound sub-query into pParent. + ** See ticket [d11a6e908f]. + */ ExprList *pOrderBy = pSub->pOrderBy; for(i=0; inExpr; i++){ pOrderBy->a[i].u.x.iOrderByCol = 0; @@ -152151,6 +153989,16 @@ static int pushDownWhereTerms( x.pEList = pSubq->pEList; x.pCList = findLeftmostExprlist(pSubq); pNew = substExpr(&x, pNew); + assert( pNew!=0 || pParse->nErr!=0 ); + if( pParse->nErr==0 && pNew->op==TK_IN && ExprUseXSelect(pNew) ){ + assert( pNew->x.pSelect!=0 ); + pNew->x.pSelect->selFlags |= SF_ClonedRhsIn; + assert( pWhere!=0 ); + assert( pWhere->op==TK_IN ); + assert( ExprUseXSelect(pWhere) ); + assert( pWhere->x.pSelect!=0 ); + pWhere->x.pSelect->selFlags |= SF_ClonedRhsIn; + } #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){ /* Restriction 6c has prevented push-down in this case */ @@ -152385,14 +154233,14 @@ SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ ** SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2) ** ORDER BY ... COLLATE ... ** -** This transformation is necessary because the multiSelectOrderBy() routine +** This transformation is necessary because the multiSelectByMerge() routine ** above that generates the code for a compound SELECT with an ORDER BY clause ** uses a merge algorithm that requires the same collating sequence on the ** result columns as on the ORDER BY clause. See ticket ** http://sqlite.org/src/info/6709574d2a ** ** This transformation is only needed for EXCEPT, INTERSECT, and UNION. -** The UNION ALL operator works fine with multiSelectOrderBy() even when +** The UNION ALL operator works fine with multiSelectByMerge() even when ** there are COLLATE terms in the ORDER BY. */ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){ @@ -152938,7 +154786,7 @@ static int selectExpander(Walker *pWalker, Select *p){ } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( ALWAYS(IsVirtual(pTab)) - && pFrom->fg.fromDDL + && (pFrom->fg.fromDDL || (pParse->prepFlags & SQLITE_PREPARE_FROM_DDL)) && ALWAYS(pTab->u.vtab.p!=0) && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0) ){ @@ -153891,7 +155739,7 @@ static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ && pExpr->pAggInfo==0 ){ sqlite3 *db = pWalker->pParse->db; - Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1"); + Expr *pNew = sqlite3ExprInt32(db, 1); if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); @@ -154242,7 +156090,6 @@ static SQLITE_NOINLINE void existsToJoin( ExprSetProperty(pWhere, EP_IntValue); assert( p->pWhere!=0 ); pSub->pSrc->a[0].fg.fromExists = 1; - pSub->pSrc->a[0].fg.jointype |= JT_CROSS; p->pSrc = sqlite3SrcListAppendList(pParse, p->pSrc, pSub->pSrc); if( pSubWhere ){ p->pWhere = sqlite3PExpr(pParse, TK_AND, p->pWhere, pSubWhere); @@ -154270,6 +156117,7 @@ typedef struct CheckOnCtx CheckOnCtx; struct CheckOnCtx { SrcList *pSrc; /* SrcList for this context */ int iJoin; /* Cursor numbers must be =< than this */ + int bFuncArg; /* True for table-function arg */ CheckOnCtx *pParent; /* Parent context */ }; @@ -154321,7 +156169,9 @@ static int selectCheckOnClausesExpr(Walker *pWalker, Expr *pExpr){ if( iTab>=pSrc->a[0].iCursor && iTab<=pSrc->a[pSrc->nSrc-1].iCursor ){ if( pCtx->iJoin && iTab>pCtx->iJoin ){ sqlite3ErrorMsg(pWalker->pParse, - "ON clause references tables to its right"); + "%s references tables to its right", + (pCtx->bFuncArg ? "table-function argument" : "ON clause") + ); return WRC_Abort; } break; @@ -154356,9 +156206,10 @@ static int selectCheckOnClausesSelect(Walker *pWalker, Select *pSelect){ ** Check all ON clauses in pSelect to verify that they do not reference ** columns to the right. */ -static void selectCheckOnClauses(Parse *pParse, Select *pSelect){ +SQLITE_PRIVATE void sqlite3SelectCheckOnClauses(Parse *pParse, Select *pSelect){ Walker w; CheckOnCtx sCtx; + int ii; assert( pSelect->selFlags & SF_OnToWhere ); assert( pSelect->pSrc!=0 && pSelect->pSrc->nSrc>=2 ); memset(&w, 0, sizeof(w)); @@ -154368,8 +156219,46 @@ static void selectCheckOnClauses(Parse *pParse, Select *pSelect){ w.u.pCheckOnCtx = &sCtx; memset(&sCtx, 0, sizeof(sCtx)); sCtx.pSrc = pSelect->pSrc; - sqlite3WalkExprNN(&w, pSelect->pWhere); + sqlite3WalkExpr(&w, pSelect->pWhere); pSelect->selFlags &= ~SF_OnToWhere; + + /* Check for any table-function args that are attached to virtual tables + ** on the RHS of an outer join. They are subject to the same constraints + ** as ON clauses. */ + sCtx.bFuncArg = 1; + for(ii=0; iipSrc->nSrc; ii++){ + SrcItem *pItem = &pSelect->pSrc->a[ii]; + if( pItem->fg.isTabFunc + && (pItem->fg.jointype & JT_OUTER) + ){ + sCtx.iJoin = pItem->iCursor; + sqlite3WalkExprList(&w, pItem->u1.pFuncArg); + } + } +} + +/* +** If p2 exists and p1 and p2 have the same number of terms, then change +** every term of p1 to have the same sort order as p2 and return true. +** +** If p2 is NULL or p1 and p2 are different lengths, then make no changes +** and return false. +** +** p1 must be non-NULL. +*/ +static int sqlite3CopySortOrder(ExprList *p1, ExprList *p2){ + assert( p1 ); + if( p2 && p1->nExpr==p2->nExpr ){ + int ii; + for(ii=0; iinExpr; ii++){ + u8 sortFlags; + sortFlags = p2->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC; + p1->a[ii].fg.sortFlags = sortFlags; + } + return 1; + }else{ + return 0; + } } /* @@ -154467,8 +156356,7 @@ SQLITE_PRIVATE int sqlite3Select( assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); if( IgnorableDistinct(pDest) ){ - assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || - pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || + assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Discard || pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo ); /* All of these destinations are also able to ignore the ORDER BY clause */ if( p->pOrderBy ){ @@ -154484,7 +156372,6 @@ SQLITE_PRIVATE int sqlite3Select( p->pOrderBy = 0; } p->selFlags &= ~(u32)SF_Distinct; - p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); if( pParse->nErr ){ @@ -154499,18 +156386,6 @@ SQLITE_PRIVATE int sqlite3Select( } #endif - /* If the SELECT statement contains ON clauses that were moved into - ** the WHERE clause, go through and verify that none of the terms - ** in the ON clauses reference tables to the right of the ON clause. - ** Do this now, after name resolution, but before query flattening - */ - if( p->selFlags & SF_OnToWhere ){ - selectCheckOnClauses(pParse, p); - if( pParse->nErr ){ - goto select_end; - } - } - /* If the SF_UFSrcCheck flag is set, then this function is being called ** as part of populating the temp table for an UPDATE...FROM statement. ** In this case, it is an error if the target object (pSrc->a[0]) name @@ -155024,7 +156899,8 @@ SQLITE_PRIVATE int sqlite3Select( ** BY and DISTINCT, and an index or separate temp-table for the other. */ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct - && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 + && sqlite3CopySortOrder(pEList, sSort.pOrderBy) + && sqlite3ExprListCompare(pEList, sSort.pOrderBy, -1)==0 && OptimizationEnabled(db, SQLITE_GroupByOrder) #ifndef SQLITE_OMIT_WINDOWFUNC && p->pWin==0 @@ -155238,21 +157114,10 @@ SQLITE_PRIVATE int sqlite3Select( ** but not actually sorted. Either way, record the fact that the ** ORDER BY and GROUP BY clauses are the same by setting the orderByGrp ** variable. */ - if( sSort.pOrderBy && pGroupBy->nExpr==sSort.pOrderBy->nExpr ){ - int ii; - /* The GROUP BY processing doesn't care whether rows are delivered in - ** ASC or DESC order - only that each group is returned contiguously. - ** So set the ASC/DESC flags in the GROUP BY to match those in the - ** ORDER BY to maximize the chances of rows being delivered in an - ** order that makes the ORDER BY redundant. */ - for(ii=0; iinExpr; ii++){ - u8 sortFlags; - sortFlags = sSort.pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC; - pGroupBy->a[ii].fg.sortFlags = sortFlags; - } - if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ - orderByGrp = 1; - } + if( sqlite3CopySortOrder(pGroupBy, sSort.pOrderBy) + && sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 + ){ + orderByGrp = 1; } }else{ assert( 0==sqlite3LogEst(1) ); @@ -156062,7 +157927,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); - sqlite3SrcListDelete(db, pTmp->pFrom); + sqlite3SrcListDelete(db, pTmp->pSrc); sqlite3DbFree(db, pTmp->zSpan); sqlite3DbFree(db, pTmp); @@ -156251,11 +158116,16 @@ SQLITE_PRIVATE void sqlite3BeginTrigger( } } + /* NB: The SQLITE_ALLOW_TRIGGERS_ON_SYSTEM_TABLES compile-time option is + ** experimental and unsupported. Do not use it unless understand the + ** implications and you cannot get by without this capability. */ +#if !defined(SQLITE_ALLOW_TRIGGERS_ON_SYSTEM_TABLES) /* Experimental */ /* Do not create a trigger on a system table */ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 ){ sqlite3ErrorMsg(pParse, "cannot create trigger on system table"); goto trigger_cleanup; } +#endif /* INSTEAD of triggers are only for views and views only support INSTEAD ** of triggers. @@ -156367,6 +158237,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + assert( iDb>=00 && iDbnDb ); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; @@ -156401,12 +158272,12 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( if( sqlite3ReadOnlyShadowTables(db) ){ TriggerStep *pStep; for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ - if( pStep->zTarget!=0 - && sqlite3ShadowTableName(db, pStep->zTarget) + if( pStep->pSrc!=0 + && sqlite3ShadowTableName(db, pStep->pSrc->a[0].zName) ){ sqlite3ErrorMsg(pParse, "trigger \"%s\" may not write to shadow table \"%s\"", - pTrig->zName, pStep->zTarget); + pTrig->zName, pStep->pSrc->a[0].zName); goto triggerfinish_cleanup; } } @@ -156497,26 +158368,39 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep( static TriggerStep *triggerStepAllocate( Parse *pParse, /* Parser context */ u8 op, /* Trigger opcode */ - Token *pName, /* The target name */ + SrcList *pTabList, /* Target table */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ + Trigger *pNew = pParse->pNewTrigger; sqlite3 *db = pParse->db; - TriggerStep *pTriggerStep; + TriggerStep *pTriggerStep = 0; - if( pParse->nErr ) return 0; - pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); - if( pTriggerStep ){ - char *z = (char*)&pTriggerStep[1]; - memcpy(z, pName->z, pName->n); - sqlite3Dequote(z); - pTriggerStep->zTarget = z; - pTriggerStep->op = op; - pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); - if( IN_RENAME_OBJECT ){ - sqlite3RenameTokenMap(pParse, pTriggerStep->zTarget, pName); + if( pParse->nErr==0 ){ + if( pNew + && pNew->pSchema!=db->aDb[1].pSchema + && pTabList->a[0].u4.zDatabase + ){ + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); + }else{ + pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep)); + if( pTriggerStep ){ + pTriggerStep->pSrc = sqlite3SrcListDup(db, pTabList, EXPRDUP_REDUCE); + pTriggerStep->op = op; + pTriggerStep->zSpan = triggerSpanDup(db, zStart, zEnd); + if( pTriggerStep->pSrc && IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, + pTriggerStep->pSrc->a[0].zName, + pTabList->a[0].zName + ); + } + } } } + + sqlite3SrcListDelete(db, pTabList); return pTriggerStep; } @@ -156529,7 +158413,7 @@ static TriggerStep *triggerStepAllocate( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( Parse *pParse, /* Parser */ - Token *pTableName, /* Name of the table into which we insert */ + SrcList *pTabList, /* Table to INSERT into */ IdList *pColumn, /* List of columns in pTableName to insert into */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf, /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ @@ -156542,7 +158426,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( assert(pSelect != 0 || db->mallocFailed); - pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_INSERT, pTabList, zStart, zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pSelect = pSelect; @@ -156574,7 +158458,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ - Token *pTableName, /* Name of the table to be updated */ + SrcList *pTabList, /* Name of the table to be updated */ SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ @@ -156585,21 +158469,36 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_UPDATE, pTabList, zStart, zEnd); if( pTriggerStep ){ + SrcList *pFromDup = 0; if( IN_RENAME_OBJECT ){ pTriggerStep->pExprList = pEList; pTriggerStep->pWhere = pWhere; - pTriggerStep->pFrom = pFrom; + pFromDup = pFrom; pEList = 0; pWhere = 0; pFrom = 0; }else{ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); - pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); + pFromDup = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE); } pTriggerStep->orconf = orconf; + + if( pFromDup && !IN_RENAME_OBJECT){ + Select *pSub; + Token as = {0, 0}; + pSub = sqlite3SelectNew(pParse, 0, pFromDup, 0,0,0,0, SF_NestedFrom, 0); + pFromDup = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, &as, pSub ,0); + } + if( pFromDup && pTriggerStep->pSrc ){ + pTriggerStep->pSrc = sqlite3SrcListAppendList( + pParse, pTriggerStep->pSrc, pFromDup + ); + }else{ + sqlite3SrcListDelete(db, pFromDup); + } } sqlite3ExprListDelete(db, pEList); sqlite3ExprDelete(db, pWhere); @@ -156614,7 +158513,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep( */ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( Parse *pParse, /* Parser */ - Token *pTableName, /* The table from which rows are deleted */ + SrcList *pTabList, /* The table from which rows are deleted */ Expr *pWhere, /* The WHERE clause */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ @@ -156622,7 +158521,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep( sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; - pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTableName,zStart,zEnd); + pTriggerStep = triggerStepAllocate(pParse, TK_DELETE, pTabList, zStart, zEnd); if( pTriggerStep ){ if( IN_RENAME_OBJECT ){ pTriggerStep->pWhere = pWhere; @@ -156822,6 +158721,7 @@ static SQLITE_NOINLINE Trigger *triggersReallyExist( p = pList; if( (pParse->db->flags & SQLITE_EnableTrigger)==0 && pTab->pTrigger!=0 + && sqlite3SchemaToIndex(pParse->db, pTab->pTrigger->pSchema)!=1 ){ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that ** only TEMP triggers are allowed. Truncate the pList so that it @@ -156884,52 +158784,6 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist( return triggersReallyExist(pParse,pTab,op,pChanges,pMask); } -/* -** Convert the pStep->zTarget string into a SrcList and return a pointer -** to that SrcList. -** -** This routine adds a specific database name, if needed, to the target when -** forming the SrcList. This prevents a trigger in one database from -** referring to a target in another database. An exception is when the -** trigger is in TEMP in which case it can refer to any other database it -** wants. -*/ -SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc( - Parse *pParse, /* The parsing context */ - TriggerStep *pStep /* The trigger containing the target token */ -){ - sqlite3 *db = pParse->db; - SrcList *pSrc; /* SrcList to be returned */ - char *zName = sqlite3DbStrDup(db, pStep->zTarget); - pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); - assert( pSrc==0 || pSrc->nSrc==1 ); - assert( zName || pSrc==0 ); - if( pSrc ){ - Schema *pSchema = pStep->pTrig->pSchema; - pSrc->a[0].zName = zName; - if( pSchema!=db->aDb[1].pSchema ){ - assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 ); - pSrc->a[0].u4.pSchema = pSchema; - pSrc->a[0].fg.fixedSchema = 1; - } - if( pStep->pFrom ){ - SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); - if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){ - Select *pSubquery; - Token as; - pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0); - as.n = 0; - as.z = 0; - pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); - } - pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); - } - }else{ - sqlite3DbFree(db, zName); - } - return pSrc; -} - /* ** Return true if the pExpr term from the RETURNING clause argument ** list is of the form "*". Raise an error if the terms if of the @@ -157195,7 +159049,7 @@ static int codeTriggerProgram( switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 @@ -157205,7 +159059,7 @@ static int codeTriggerProgram( } case TK_INSERT: { sqlite3Insert(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf, @@ -157216,7 +159070,7 @@ static int codeTriggerProgram( } case TK_DELETE: { sqlite3DeleteFrom(pParse, - sqlite3TriggerStepSrc(pParse, pStep), + sqlite3SrcListDup(db, pStep->pSrc, 0), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); sqlite3VdbeAddOp0(v, OP_ResetCount); @@ -159538,9 +161392,11 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( pDb = &db->aDb[nDb]; assert( strcmp(pDb->zDbSName,zDbVacuum)==0 ); pTemp = pDb->pBt; + nRes = sqlite3BtreeGetRequestedReserve(pMain); if( pOut ){ sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp)); i64 sz = 0; + const char *zFilename; if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){ rc = SQLITE_ERROR; sqlite3SetString(pzErrMsg, db, "output file already exists"); @@ -159552,8 +161408,16 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum( ** they are for the database being vacuumed, except that PAGER_CACHESPILL ** is always set. */ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK); + + /* If the VACUUM INTO target file is a URI filename and if the + ** "reserve=N" query parameter is present, reset the reserve to the + ** amount specified, if the amount is within range */ + zFilename = sqlite3BtreeGetFilename(pTemp); + if( ALWAYS(zFilename) ){ + int nNew = (int)sqlite3_uri_int64(zFilename, "reserve", nRes); + if( nNew>=0 && nNew<=255 ) nRes = nNew; + } } - nRes = sqlite3BtreeGetRequestedReserve(pMain); sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size); sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0)); @@ -163358,7 +165222,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart( if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){ int iTab = pParse->nTab++; int iCache = ++pParse->nMem; - sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab); + sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab, 0); sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache); }else{ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); @@ -164677,6 +166541,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } } + if( pLevel->iIdxCur ){ + /* pSubWhere may contain expressions that read from an index on the + ** table on the RHS of the right join. All such expressions first test + ** if the index is pointing at a NULL row, and if so, read from the + ** table cursor instead. So ensure that the index cursor really is + ** pointing at a NULL row here, so that no values are read from it during + ** the scan of the RHS of the RIGHT join below. */ + sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); + } pFrom = &uSrc.sSrc; pFrom->nSrc = 1; pFrom->nAlloc = 1; @@ -165017,13 +166890,14 @@ static int isLikeOrGlob( ){ int isNum; double rDummy; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + assert( zNew[iTo]==0 ); + isNum = sqlite3AtoF(zNew, &rDummy); if( isNum<=0 ){ if( iTo==1 && zNew[0]=='-' ){ isNum = +1; }else{ zNew[iTo-1]++; - isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8); + isNum = sqlite3AtoF(zNew, &rDummy); zNew[iTo-1]--; } } @@ -165066,6 +166940,34 @@ static int isLikeOrGlob( } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ +/* +** If pExpr is one of "like", "glob", "match", or "regexp", then +** return the corresponding SQLITE_INDEX_CONSTRAINT_xxxx value. +** If not, return 0. +** +** pExpr is guaranteed to be a TK_FUNCTION. +*/ +SQLITE_PRIVATE int sqlite3ExprIsLikeOperator(const Expr *pExpr){ + static const struct { + const char *zOp; + unsigned char eOp; + } aOp[] = { + { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, + { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, + { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, + { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } + }; + int i; + assert( pExpr->op==TK_FUNCTION ); + assert( !ExprHasProperty(pExpr, EP_IntValue) ); + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + return aOp[i].eOp; + } + } + return 0; +} + #ifndef SQLITE_OMIT_VIRTUALTABLE /* @@ -165102,15 +167004,6 @@ static int isAuxiliaryVtabOperator( Expr **ppRight /* Expression to left of MATCH/op2 */ ){ if( pExpr->op==TK_FUNCTION ){ - static const struct Op2 { - const char *zOp; - unsigned char eOp2; - } aOp[] = { - { "match", SQLITE_INDEX_CONSTRAINT_MATCH }, - { "glob", SQLITE_INDEX_CONSTRAINT_GLOB }, - { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, - { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } - }; ExprList *pList; Expr *pCol; /* Column reference */ int i; @@ -165130,16 +167023,11 @@ static int isAuxiliaryVtabOperator( */ pCol = pList->a[1].pExpr; assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) ); - if( ExprIsVtab(pCol) ){ - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - *ppRight = pList->a[0].pExpr; - *ppLeft = pCol; - return 1; - } - } + if( ExprIsVtab(pCol) && (i = sqlite3ExprIsLikeOperator(pExpr))!=0 ){ + *peOp2 = i; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; } /* We can also match against the first column of overloaded @@ -165273,16 +167161,22 @@ static void whereCombineDisjuncts( Expr *pNew; /* New virtual expression */ int op; /* Operator for the combined expression */ int idxNew; /* Index in pWC of the next virtual term */ + Expr *pA, *pB; /* Expressions associated with pOne and pTwo */ if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return; if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return; if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp && (eOp & (WO_EQ|WO_GT|WO_GE))!=eOp ) return; - assert( pOne->pExpr->pLeft!=0 && pOne->pExpr->pRight!=0 ); - assert( pTwo->pExpr->pLeft!=0 && pTwo->pExpr->pRight!=0 ); - if( sqlite3ExprCompare(0,pOne->pExpr->pLeft, pTwo->pExpr->pLeft, -1) ) return; - if( sqlite3ExprCompare(0,pOne->pExpr->pRight, pTwo->pExpr->pRight,-1) )return; + pA = pOne->pExpr; + pB = pTwo->pExpr; + assert( pA->pLeft!=0 && pA->pRight!=0 ); + assert( pB->pLeft!=0 && pB->pRight!=0 ); + if( sqlite3ExprCompare(0,pA->pLeft, pB->pLeft, -1) ) return; + if( sqlite3ExprCompare(0,pA->pRight, pB->pRight,-1) ) return; + if( ExprHasProperty(pA,EP_Commuted)!=ExprHasProperty(pB,EP_Commuted) ){ + return; + } /* If we reach this point, it means the two subterms can be combined */ if( (eOp & (eOp-1))!=0 ){ if( eOp & (WO_LT|WO_LE) ){ @@ -165293,7 +167187,7 @@ static void whereCombineDisjuncts( } } db = pWC->pWInfo->pParse->db; - pNew = sqlite3ExprDup(db, pOne->pExpr, 0); + pNew = sqlite3ExprDup(db, pA, 0); if( pNew==0 ) return; for(op=TK_EQ; eOp!=(WO_EQ<<(op-TK_EQ)); op++){ assert( opop = op; @@ -166333,13 +168227,11 @@ static void whereAddLimitExpr( int iVal = 0; if( sqlite3ExprIsInteger(pExpr, &iVal, pParse) && iVal>=0 ){ - Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0); + Expr *pVal = sqlite3ExprInt32(db, iVal); if( pVal==0 ) return; - ExprSetProperty(pVal, EP_IntValue); - pVal->u.iValue = iVal; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); }else{ - Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0); + Expr *pVal = sqlite3ExprAlloc(db, TK_REGISTER, 0, 0); if( pVal==0 ) return; pVal->iTable = iReg; pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal); @@ -168166,11 +170058,14 @@ static sqlite3_index_info *allocateIndexInfo( break; } if( i==n ){ + int bSortByGroup = (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0; nOrderBy = n; if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) && !pSrc->fg.rowidUsed ){ - eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0); + eDistinct = 2 + bSortByGroup; }else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){ - eDistinct = 1; + eDistinct = 1 - bSortByGroup; + }else if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){ + eDistinct = 3; } } } @@ -169098,11 +170993,16 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){ SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ WhereInfo *pWInfo; if( pWC ){ + int nb; + SrcItem *pItem; + Table *pTab; + Bitmask mAll; + pWInfo = pWC->pWInfo; - int nb = 1+(pWInfo->pTabList->nSrc+3)/4; - SrcItem *pItem = pWInfo->pTabList->a + p->iTab; - Table *pTab = pItem->pSTab; - Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; + nb = 1+(pWInfo->pTabList->nSrc+3)/4; + pItem = pWInfo->pTabList->a + p->iTab; + pTab = pItem->pSTab; + mAll = (((Bitmask)1)<<(nb*4)) - 1; sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); sqlite3DebugPrintf(" %12s", @@ -169581,6 +171481,67 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ return rc; } +/* +** Callback for estLikePatternLength(). +** +** If this node is a string literal that is longer pWalker->sz, then set +** pWalker->sz to the byte length of that string literal. +** +** pWalker->eCode indicates how to count characters: +** +** eCode==0 Count as a GLOB pattern +** eCode==1 Count as a LIKE pattern +*/ +static int exprNodePatternLengthEst(Walker *pWalker, Expr *pExpr){ + if( pExpr->op==TK_STRING ){ + int sz = 0; /* Pattern size in bytes */ + u8 *z = (u8*)pExpr->u.zToken; /* The pattern */ + u8 c; /* Next character of the pattern */ + u8 c1, c2, c3; /* Wildcards */ + if( pWalker->eCode ){ + c1 = '%'; + c2 = '_'; + c3 = 0; + }else{ + c1 = '*'; + c2 = '?'; + c3 = '['; + } + while( (c = *(z++))!=0 ){ + if( c==c3 ){ + if( *z ) z++; + while( *z && *z!=']' ) z++; + }else if( c!=c1 && c!=c2 ){ + sz++; + } + } + if( sz>pWalker->u.sz ) pWalker->u.sz = sz; + } + return WRC_Continue; +} + +/* +** Return the length of the longest string literal in the given +** expression. +** +** eCode indicates how to count characters: +** +** eCode==0 Count as a GLOB pattern +** eCode==1 Count as a LIKE pattern +*/ +static int estLikePatternLength(Expr *p, u16 eCode){ + Walker w; + w.u.sz = 0; + w.eCode = eCode; + w.xExprCallback = exprNodePatternLengthEst; + w.xSelectCallback = sqlite3SelectWalkFail; +#ifdef SQLITE_DEBUG + w.xSelectCallback2 = sqlite3SelectWalkAssert2; +#endif + sqlite3WalkExpr(&w, p); + return w.u.sz; +} + /* ** Adjust the WhereLoop.nOut value downward to account for terms of the ** WHERE clause that reference the loop but which are not used by an @@ -169609,6 +171570,13 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){ ** "x" column is boolean or else -1 or 0 or 1 is a common default value ** on the "x" column and so in that case only cap the output row estimate ** at 1/2 instead of 1/4. +** +** Heuristic 3: If there is a LIKE or GLOB (or REGEXP or MATCH) operator +** with a large constant pattern, then reduce the size of the search +** space according to the length of the pattern, under the theory that +** longer patterns are less likely to match. This heuristic was added +** to give better output-row count estimates when preparing queries for +** the Join-Order Benchmarks. See forum thread 2026-01-30T09:57:54z */ static void whereLoopOutputAdjust( WhereClause *pWC, /* The WHERE clause */ @@ -169658,13 +171626,14 @@ static void whereLoopOutputAdjust( }else{ /* In the absence of explicit truth probabilities, use heuristics to ** guess a reasonable truth probability. */ + Expr *pOpExpr = pTerm->pExpr; pLoop->nOut--; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */ ){ - Expr *pRight = pTerm->pExpr->pRight; + Expr *pRight = pOpExpr->pRight; int k = 0; - testcase( pTerm->pExpr->op==TK_IS ); + testcase( pOpExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k, 0) && k>=(-1) && k<=1 ){ k = 10; }else{ @@ -169674,6 +171643,23 @@ static void whereLoopOutputAdjust( pTerm->wtFlags |= TERM_HEURTRUTH; iReduce = k; } + }else + if( ExprHasProperty(pOpExpr, EP_InfixFunc) + && pOpExpr->op==TK_FUNCTION + ){ + int eOp; + assert( ExprUseXList(pOpExpr) ); + assert( pOpExpr->x.pList->nExpr>=2 ); + eOp = sqlite3ExprIsLikeOperator(pOpExpr); + if( ALWAYS(eOp>0) ){ + int szPattern; + Expr *pRHS = pOpExpr->x.pList->a[0].pExpr; + eOp = eOp==SQLITE_INDEX_CONSTRAINT_LIKE; + szPattern = estLikePatternLength(pRHS, eOp); + if( szPattern>0 ){ + pLoop->nOut -= szPattern*2; + } + } } } } @@ -169745,7 +171731,7 @@ static int whereRangeVectorLen( idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn); if( aff!=idxaff ) break; - pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); + pColl = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr); if( pColl==0 ) break; if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break; } @@ -170134,6 +172120,7 @@ static int whereLoopAddBtreeIndex( pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); + if( pSrc->fg.fromExists ) pNew->nOut = 0; rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ @@ -170729,7 +172716,14 @@ static int whereLoopAddBtree( whereLoopOutputAdjust(pWC, pNew, rSize); if( pSrc->fg.isSubquery ){ if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; - pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; + /* Do not set btree.pOrderBy for a recursive CTE. In this case + ** the ORDER BY clause does not determine the overall order that + ** rows are emitted from the CTE in. */ + if( (pSrc->u4.pSubq->pSelect->selFlags & SF_Recursive)==0 ){ + pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; + } + }else if( pSrc->fg.fromExists ){ + pNew->nOut = 0; } rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; @@ -170832,6 +172826,7 @@ static int whereLoopAddBtree( ** positioned to the correct row during the right-join no-match ** loop. */ }else{ + if( pSrc->fg.fromExists ) pNew->nOut = 0; rc = whereLoopInsert(pBuilder, pNew); } pNew->nOut = rSize; @@ -171494,7 +173489,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; int bFirstPastRJ = 0; - int hasRightJoin = 0; + int hasRightCrossJoin = 0; WhereLoop *pNew; @@ -171521,15 +173516,34 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ ** prevents the right operand of a RIGHT JOIN from being swapped with ** other elements even further to the right. ** - ** The JT_LTORJ case and the hasRightJoin flag work together to - ** prevent FROM-clause terms from moving from the right side of - ** a LEFT JOIN over to the left side of that join if the LEFT JOIN - ** is itself on the left side of a RIGHT JOIN. + ** The hasRightCrossJoin flag prevent FROM-clause terms from moving + ** from the right side of a LEFT JOIN or CROSS JOIN over to the + ** left side of that same join. This is a required restriction in + ** the case of LEFT JOIN - an incorrect answer may results if it is + ** not enforced. This restriction is not required for CROSS JOIN. + ** It is provided merely as a means of controlling join order, under + ** the theory that no real-world queries that care about performance + ** actually use the CROSS JOIN syntax. */ - if( pItem->fg.jointype & JT_LTORJ ) hasRightJoin = 1; + if( pItem->fg.jointype & (JT_LTORJ|JT_CROSS) ){ + testcase( pItem->fg.jointype & JT_LTORJ ); + testcase( pItem->fg.jointype & JT_CROSS ); + hasRightCrossJoin = 1; + } mPrereq |= mPrior; bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; - }else if( !hasRightJoin ){ + }else if( pItem->fg.fromExists ){ + /* joins that result from the EXISTS-to-JOIN optimization should not + ** be moved to the left of any of their dependencies */ + WhereClause *pWC = &pWInfo->sWC; + WhereTerm *pTerm; + int i; + for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){ + if( (pNew->maskSelf & pTerm->prereqAll)!=0 ){ + mPrereq |= (pTerm->prereqAll & (pNew->maskSelf-1)); + } + } + }else if( !hasRightCrossJoin ){ mPrereq = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE @@ -171752,9 +173766,7 @@ static i8 wherePathSatisfiesOrderBy( pLoop = pLast; } if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ - if( pLoop->u.vtab.isOrdered - && ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY) - ){ + if( pLoop->u.vtab.isOrdered && pWInfo->pOrderBy==pOrderBy ){ obSat = obDone; }else{ /* No further ORDER BY terms may be matched. So this call should @@ -172130,12 +174142,21 @@ static LogEst whereSortingCost( ** 12 otherwise ** ** For the purposes of this heuristic, a star-query is defined as a query -** with a large central table that is joined using an INNER JOIN, -** not CROSS or OUTER JOINs, against four or more smaller tables. -** The central table is called the "fact" table. The smaller tables -** that get joined are "dimension tables". Also, any table that is -** self-joined cannot be a dimension table; we assume that dimension -** tables may only be joined against fact tables. +** with a central "fact" table that is joined against multiple +** "dimension" tables, subject to the following constraints: +** +** (aa) Only a five-way or larger join is considered for this +** optimization. If there are fewer than four terms in the FROM +** clause, this heuristic does not apply. +** +** (bb) The join between the fact table and the dimension tables must +** be an INNER join. CROSS and OUTER JOINs do not qualify. +** +** (cc) A table must have 3 or more dimension tables in order to be +** considered a fact table. (Was 4 prior to 2026-02-10.) +** +** (dd) A table that is a self-join cannot be a dimension table. +** Dimension tables are joined against fact tables. ** ** SIDE EFFECT: (and really the whole point of this subroutine) ** @@ -172188,7 +174209,7 @@ static int computeMxChoice(WhereInfo *pWInfo){ } #endif /* SQLITE_DEBUG */ - if( nLoop>=5 + if( nLoop>=4 /* Constraint (aa) */ && !pWInfo->bStarDone && OptimizationEnabled(pWInfo->pParse->db, SQLITE_StarQuery) ){ @@ -172200,7 +174221,7 @@ static int computeMxChoice(WhereInfo *pWInfo){ pWInfo->bStarDone = 1; /* Only do this computation once */ - /* Look for fact tables with four or more dimensions where the + /* Look for fact tables with three or more dimensions where the ** dimension tables are not separately from the fact tables by an outer ** or cross join. Adjust cost weights if found. */ @@ -172217,18 +174238,17 @@ static int computeMxChoice(WhereInfo *pWInfo){ if( (pFactTab->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ /* If the candidate fact-table is the right table of an outer join ** restrict the search for dimension-tables to be tables to the right - ** of the fact-table. */ - if( iFromIdx+4 > nLoop ) break; /* Impossible to reach nDep>=4 */ + ** of the fact-table. Constraint (bb) */ + if( iFromIdx+3 > nLoop ){ + break; /* ^-- Impossible to reach nDep>=2 - Constraint (cc) */ + } while( pStart && pStart->iTab<=iFromIdx ){ pStart = pStart->pNextLoop; } } for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ if( (aFromTabs[pWLoop->iTab].fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ - /* Fact-tables and dimension-tables cannot be separated by an - ** outer join (at least for the definition of fact- and dimension- - ** used by this heuristic). */ - break; + break; /* Constraint (bb) */ } if( (pWLoop->prereq & m)!=0 /* pWInfo depends on iFromIdx */ && (pWLoop->maskSelf & mSeen)==0 /* pWInfo not already a dependency */ @@ -172242,7 +174262,9 @@ static int computeMxChoice(WhereInfo *pWInfo){ } } } - if( nDep<=3 ) continue; + if( nDep<=2 ){ + continue; /* Constraint (cc) */ + } /* If we reach this point, it means that pFactTab is a fact table ** with four or more dimensions connected by inner joins. Proceed @@ -172255,6 +174277,23 @@ static int computeMxChoice(WhereInfo *pWInfo){ pWLoop->rStarDelta = 0; } } +#endif +#ifdef WHERETRACE_ENABLED /* 0x80000 */ + if( sqlite3WhereTrace & 0x80000 ){ + Bitmask mShow = mSeen; + sqlite3DebugPrintf("Fact table %s(%d), dimensions:", + pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, + iFromIdx); + for(pWLoop=pStart; pWLoop; pWLoop=pWLoop->pNextLoop){ + if( mShow & pWLoop->maskSelf ){ + SrcItem *pDim = aFromTabs + pWLoop->iTab; + mShow &= ~pWLoop->maskSelf; + sqlite3DebugPrintf(" %s(%d)", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab); + } + } + sqlite3DebugPrintf("\n"); + } #endif pWInfo->bStarUsed = 1; @@ -172278,10 +174317,8 @@ static int computeMxChoice(WhereInfo *pWInfo){ if( sqlite3WhereTrace & 0x80000 ){ SrcItem *pDim = aFromTabs + pWLoop->iTab; sqlite3DebugPrintf( - "Increase SCAN cost of dimension %s(%d) of fact %s(%d) to %d\n", - pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, pWLoop->iTab, - pFactTab->zAlias ? pFactTab->zAlias : pFactTab->pSTab->zName, - iFromIdx, mxRun + "Increase SCAN cost of %s to %d\n", + pDim->zAlias ? pDim->zAlias: pDim->pSTab->zName, mxRun ); } pWLoop->rStarDelta = mxRun - pWLoop->rRun; @@ -173095,6 +175132,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ pTerm->wtFlags |= TERM_CODED; + pTerm->prereqAll = 0; } } if( i!=pWInfo->nLevel-1 ){ @@ -174070,6 +176108,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ ){ int r1 = pParse->nMem+1; int j, op; + int addrIfNull = 0; /* Init to avoid false-positive compiler warning */ + if( pLevel->iLeftJoin ){ + addrIfNull = sqlite3VdbeAddOp2(v, OP_IfNullRow, pLevel->iIdxCur, r1); + } for(j=0; jiIdxCur, j, r1+j); } @@ -174079,17 +176121,21 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ VdbeCoverageIf(v, op==OP_SeekLT); VdbeCoverageIf(v, op==OP_SeekGT); sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); + if( pLevel->iLeftJoin ){ + sqlite3VdbeJumpHere(v, addrIfNull); + } } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ } - if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){ - /* If the EXISTS-to-JOIN optimization was applied, then the EXISTS - ** loop(s) will be the inner-most loops of the join. There might be - ** multiple EXISTS loops, but they will all be nested, and the join - ** order will not have been changed by the query planner. If the - ** inner-most EXISTS loop sees a single successful row, it should - ** break out of *all* EXISTS loops. But only the inner-most of the - ** nested EXISTS loops should do this breakout. */ + if( pTabList->a[pLevel->iFrom].fg.fromExists + && (i==pWInfo->nLevel-1 + || pTabList->a[pWInfo->a[i+1].iFrom].fg.fromExists==0) + ){ + /* This is an EXISTS-to-JOIN optimization which is either the + ** inner-most loop, or the inner-most of a group of nested + ** EXISTS-to-JOIN optimization loops. If this loop sees a successful + ** row, it should break out of itself as well as other EXISTS-to-JOIN + ** loops in which is is directly nested. */ int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */ while( nOutera[pLevel[-nOuter-1].iFrom].fg.fromExists ) break; @@ -174097,7 +176143,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){ } testcase( nOuter>0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk); - VdbeComment((v, "EXISTS break")); + if( nOuter ){ + VdbeComment((v, "EXISTS break %d..%d", i-nOuter, i)); + }else{ + VdbeComment((v, "EXISTS break %d", i)); + } } sqlite3VdbeResolveLabel(v, pLevel->addrCont); if( pLevel->op!=OP_Noop ){ @@ -175114,7 +177164,7 @@ SQLITE_PRIVATE void sqlite3WindowUpdate( pWin->eEnd = aUp[i].eEnd; pWin->eExclude = 0; if( pWin->eStart==TK_FOLLOWING ){ - pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); + pWin->pStart = sqlite3ExprInt32(db, 1); } break; } @@ -175459,9 +177509,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){ ** keep everything legal in this case. */ if( pSublist==0 ){ - pSublist = sqlite3ExprListAppend(pParse, 0, - sqlite3Expr(db, TK_INTEGER, "0") - ); + pSublist = sqlite3ExprListAppend(pParse, 0, sqlite3ExprInt32(db, 0)); } pSub = sqlite3SelectNew( @@ -177685,8 +179733,23 @@ static void updateDeleteLimitError( ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate ** testing. */ - static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ - return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); + static void *parserStackRealloc( + void *pOld, /* Prior allocation */ + sqlite3_uint64 newSize, /* Requested new alloation size */ + Parse *pParse /* Parsing context */ + ){ + void *p = sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); + if( p==0 ) sqlite3OomFault(pParse->db); + return p; + } + static void parserStackFree(void *pOld, Parse *pParse){ + (void)pParse; + sqlite3_free(pOld); + } + + /* Return an integer that is the maximum allowed stack size */ + static int parserStackSizeLimit(Parse *pParse){ + return pParse->db->aLimit[SQLITE_LIMIT_PARSER_DEPTH]; } @@ -177725,15 +179788,46 @@ static void updateDeleteLimitError( } - /* A routine to convert a binary TK_IS or TK_ISNOT expression into a - ** unary TK_ISNULL or TK_NOTNULL expression. */ - static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ - sqlite3 *db = pParse->db; - if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ - pA->op = (u8)op; - sqlite3ExprDelete(db, pA->pRight); - pA->pRight = 0; + /* Create a TK_ISNULL or TK_NOTNULL expression, perhaps optimized to + ** to TK_TRUEFALSE, if possible */ + static Expr *sqlite3PExprIsNull( + Parse *pParse, /* Parsing context */ + int op, /* TK_ISNULL or TK_NOTNULL */ + Expr *pLeft /* Operand */ + ){ + Expr *p = pLeft; + assert( op==TK_ISNULL || op==TK_NOTNULL ); + assert( pLeft!=0 ); + while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ + p = p->pLeft; + assert( p!=0 ); } + switch( p->op ){ + case TK_INTEGER: + case TK_STRING: + case TK_FLOAT: + case TK_BLOB: + sqlite3ExprDeferredDelete(pParse, pLeft); + return sqlite3ExprInt32(pParse->db, op==TK_NOTNULL); + default: + break; + } + return sqlite3PExpr(pParse, op, pLeft, 0); + } + + /* Create a TK_IS or TK_ISNOT operator, perhaps optimized to + ** TK_ISNULL or TK_NOTNULL or TK_TRUEFALSE. */ + static Expr *sqlite3PExprIs( + Parse *pParse, /* Parsing context */ + int op, /* TK_IS or TK_ISNOT */ + Expr *pLeft, /* Left operand */ + Expr *pRight /* Right operand */ + ){ + if( pRight && pRight->op==TK_NULL ){ + sqlite3ExprDeferredDelete(pParse, pRight); + return sqlite3PExprIsNull(pParse, op==TK_IS ? TK_ISNULL : TK_NOTNULL, pLeft); + } + return sqlite3PExpr(pParse, op, pLeft, pRight); } /* Add a single new term to an ExprList that is used to store a @@ -178016,63 +180110,72 @@ static void updateDeleteLimitError( #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned short int -#define YYNOCODE 323 +#define YYNOCODE 322 #define YYACTIONTYPE unsigned short int #define YYWILDCARD 102 #define sqlite3ParserTOKENTYPE Token typedef union { int yyinit; sqlite3ParserTOKENTYPE yy0; - u32 yy9; - struct TrigEvent yy28; - With* yy125; - IdList* yy204; - struct FrameBound yy205; - TriggerStep* yy319; - const char* yy342; - Cte* yy361; - ExprList* yy402; - Upsert* yy403; - OnOrUsing yy421; - u8 yy444; - struct {int value; int mask;} yy481; - Window* yy483; - int yy502; - SrcList* yy563; - Expr* yy590; - Select* yy637; + ExprList* yy14; + With* yy59; + Cte* yy67; + Upsert* yy122; + IdList* yy132; + int yy144; + const char* yy168; + SrcList* yy203; + Window* yy211; + OnOrUsing yy269; + struct TrigEvent yy286; + struct {int value; int mask;} yy383; + u32 yy391; + TriggerStep* yy427; + Expr* yy454; + u8 yy462; + struct FrameBound yy509; + Select* yy555; } YYMINORTYPE; #ifndef YYSTACKDEPTH -#define YYSTACKDEPTH 100 +#define YYSTACKDEPTH 50 #endif #define sqlite3ParserARG_SDECL #define sqlite3ParserARG_PDECL #define sqlite3ParserARG_PARAM #define sqlite3ParserARG_FETCH #define sqlite3ParserARG_STORE +#undef YYREALLOC #define YYREALLOC parserStackRealloc -#define YYFREE sqlite3_free +#undef YYFREE +#define YYFREE parserStackFree +#undef YYDYNSTACK #define YYDYNSTACK 1 +#undef YYSIZELIMIT +#define YYSIZELIMIT parserStackSizeLimit +#define sqlite3ParserCTX(P) ((P)->pParse) #define sqlite3ParserCTX_SDECL Parse *pParse; #define sqlite3ParserCTX_PDECL ,Parse *pParse #define sqlite3ParserCTX_PARAM ,pParse #define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse; #define sqlite3ParserCTX_STORE yypParser->pParse=pParse; +#undef YYERRORSYMBOL +#undef YYERRSYMDT +#undef YYFALLBACK #define YYFALLBACK 1 -#define YYNSTATE 583 -#define YYNRULE 409 -#define YYNRULE_WITH_ACTION 344 +#define YYNSTATE 600 +#define YYNRULE 412 +#define YYNRULE_WITH_ACTION 348 #define YYNTOKEN 187 -#define YY_MAX_SHIFT 582 -#define YY_MIN_SHIFTREDUCE 845 -#define YY_MAX_SHIFTREDUCE 1253 -#define YY_ERROR_ACTION 1254 -#define YY_ACCEPT_ACTION 1255 -#define YY_NO_ACTION 1256 -#define YY_MIN_REDUCE 1257 -#define YY_MAX_REDUCE 1665 +#define YY_MAX_SHIFT 599 +#define YY_MIN_SHIFTREDUCE 867 +#define YY_MAX_SHIFTREDUCE 1278 +#define YY_ERROR_ACTION 1279 +#define YY_ACCEPT_ACTION 1280 +#define YY_NO_ACTION 1281 +#define YY_MIN_REDUCE 1282 +#define YY_MAX_REDUCE 1693 #define YY_MIN_DSTRCTR 206 -#define YY_MAX_DSTRCTR 320 +#define YY_MAX_DSTRCTR 319 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) @@ -178155,643 +180258,680 @@ typedef union { ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ -#define YY_ACTTAB_COUNT (2207) +#define YY_ACTTAB_COUNT (2379) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 130, 127, 234, 282, 282, 1328, 576, 1307, 460, 289, - /* 10 */ 289, 576, 1622, 381, 576, 1328, 573, 576, 562, 413, - /* 20 */ 1300, 1542, 573, 481, 562, 524, 460, 459, 558, 82, - /* 30 */ 82, 983, 294, 375, 51, 51, 498, 61, 61, 984, - /* 40 */ 82, 82, 1577, 137, 138, 91, 7, 1228, 1228, 1063, - /* 50 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 413, - /* 60 */ 288, 288, 182, 288, 288, 481, 536, 288, 288, 130, - /* 70 */ 127, 234, 432, 573, 525, 562, 573, 557, 562, 1290, - /* 80 */ 573, 421, 562, 137, 138, 91, 559, 1228, 1228, 1063, - /* 90 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 296, - /* 100 */ 460, 398, 1249, 134, 134, 134, 134, 133, 133, 132, - /* 110 */ 132, 132, 131, 128, 451, 451, 1050, 1050, 1064, 1067, - /* 120 */ 1255, 1, 1, 582, 2, 1259, 581, 1174, 1259, 1174, - /* 130 */ 321, 413, 155, 321, 1584, 155, 379, 112, 481, 1341, - /* 140 */ 456, 299, 1341, 134, 134, 134, 134, 133, 133, 132, - /* 150 */ 132, 132, 131, 128, 451, 137, 138, 91, 498, 1228, - /* 160 */ 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, - /* 170 */ 136, 1204, 862, 1281, 288, 288, 283, 288, 288, 523, - /* 180 */ 523, 1250, 139, 578, 7, 578, 1345, 573, 1169, 562, - /* 190 */ 573, 1054, 562, 136, 136, 136, 136, 129, 573, 547, - /* 200 */ 562, 1169, 245, 1541, 1169, 245, 133, 133, 132, 132, - /* 210 */ 132, 131, 128, 451, 302, 134, 134, 134, 134, 133, - /* 220 */ 133, 132, 132, 132, 131, 128, 451, 1575, 1204, 1205, - /* 230 */ 1204, 7, 470, 550, 455, 413, 550, 455, 130, 127, - /* 240 */ 234, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 250 */ 131, 128, 451, 136, 136, 136, 136, 538, 483, 137, - /* 260 */ 138, 91, 1019, 1228, 1228, 1063, 1066, 1053, 1053, 135, - /* 270 */ 135, 136, 136, 136, 136, 1085, 576, 1204, 132, 132, - /* 280 */ 132, 131, 128, 451, 93, 214, 134, 134, 134, 134, - /* 290 */ 133, 133, 132, 132, 132, 131, 128, 451, 401, 19, - /* 300 */ 19, 134, 134, 134, 134, 133, 133, 132, 132, 132, - /* 310 */ 131, 128, 451, 1498, 426, 267, 344, 467, 332, 134, - /* 320 */ 134, 134, 134, 133, 133, 132, 132, 132, 131, 128, - /* 330 */ 451, 1281, 576, 6, 1204, 1205, 1204, 257, 576, 413, - /* 340 */ 511, 508, 507, 1279, 94, 1019, 464, 1204, 551, 551, - /* 350 */ 506, 1224, 1571, 44, 38, 51, 51, 411, 576, 413, - /* 360 */ 45, 51, 51, 137, 138, 91, 530, 1228, 1228, 1063, - /* 370 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 398, - /* 380 */ 1148, 82, 82, 137, 138, 91, 39, 1228, 1228, 1063, - /* 390 */ 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, 344, - /* 400 */ 44, 288, 288, 375, 1204, 1205, 1204, 209, 1204, 1224, - /* 410 */ 320, 567, 471, 576, 573, 576, 562, 576, 316, 264, - /* 420 */ 231, 46, 160, 134, 134, 134, 134, 133, 133, 132, - /* 430 */ 132, 132, 131, 128, 451, 303, 82, 82, 82, 82, - /* 440 */ 82, 82, 442, 134, 134, 134, 134, 133, 133, 132, - /* 450 */ 132, 132, 131, 128, 451, 1582, 544, 320, 567, 1250, - /* 460 */ 874, 1582, 380, 382, 413, 1204, 1205, 1204, 360, 182, - /* 470 */ 288, 288, 1576, 557, 1339, 557, 7, 557, 1277, 472, - /* 480 */ 346, 526, 531, 573, 556, 562, 439, 1511, 137, 138, - /* 490 */ 91, 219, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, - /* 500 */ 136, 136, 136, 136, 465, 1511, 1513, 532, 413, 288, - /* 510 */ 288, 423, 512, 288, 288, 411, 288, 288, 874, 130, - /* 520 */ 127, 234, 573, 1107, 562, 1204, 573, 1107, 562, 573, - /* 530 */ 560, 562, 137, 138, 91, 1293, 1228, 1228, 1063, 1066, - /* 540 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 134, 134, - /* 550 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451, - /* 560 */ 493, 503, 1292, 1204, 257, 288, 288, 511, 508, 507, - /* 570 */ 1204, 1628, 1169, 123, 568, 275, 4, 506, 573, 1511, - /* 580 */ 562, 331, 1204, 1205, 1204, 1169, 548, 548, 1169, 261, - /* 590 */ 571, 7, 134, 134, 134, 134, 133, 133, 132, 132, - /* 600 */ 132, 131, 128, 451, 108, 533, 130, 127, 234, 1204, - /* 610 */ 448, 447, 413, 1451, 452, 983, 886, 96, 1598, 1233, - /* 620 */ 1204, 1205, 1204, 984, 1235, 1450, 565, 1204, 1205, 1204, - /* 630 */ 229, 522, 1234, 534, 1333, 1333, 137, 138, 91, 1449, - /* 640 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 650 */ 136, 136, 373, 1595, 971, 1040, 413, 1236, 418, 1236, - /* 660 */ 879, 121, 121, 948, 373, 1595, 1204, 1205, 1204, 122, - /* 670 */ 1204, 452, 577, 452, 363, 417, 1028, 882, 373, 1595, - /* 680 */ 137, 138, 91, 462, 1228, 1228, 1063, 1066, 1053, 1053, - /* 690 */ 135, 135, 136, 136, 136, 136, 134, 134, 134, 134, - /* 700 */ 133, 133, 132, 132, 132, 131, 128, 451, 1028, 1028, - /* 710 */ 1030, 1031, 35, 570, 570, 570, 197, 423, 1040, 198, - /* 720 */ 1204, 123, 568, 1204, 4, 320, 567, 1204, 1205, 1204, - /* 730 */ 40, 388, 576, 384, 882, 1029, 423, 1188, 571, 1028, - /* 740 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 750 */ 128, 451, 529, 1568, 1204, 19, 19, 1204, 575, 492, - /* 760 */ 413, 157, 452, 489, 1187, 1331, 1331, 5, 1204, 949, - /* 770 */ 431, 1028, 1028, 1030, 565, 22, 22, 1204, 1205, 1204, - /* 780 */ 1204, 1205, 1204, 477, 137, 138, 91, 212, 1228, 1228, - /* 790 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 800 */ 1188, 48, 111, 1040, 413, 1204, 213, 970, 1041, 121, - /* 810 */ 121, 1204, 1205, 1204, 1204, 1205, 1204, 122, 221, 452, - /* 820 */ 577, 452, 44, 487, 1028, 1204, 1205, 1204, 137, 138, - /* 830 */ 91, 378, 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, - /* 840 */ 136, 136, 136, 136, 134, 134, 134, 134, 133, 133, - /* 850 */ 132, 132, 132, 131, 128, 451, 1028, 1028, 1030, 1031, - /* 860 */ 35, 461, 1204, 1205, 1204, 1569, 1040, 377, 214, 1149, - /* 870 */ 1657, 535, 1657, 437, 902, 320, 567, 1568, 364, 320, - /* 880 */ 567, 412, 329, 1029, 519, 1188, 3, 1028, 134, 134, - /* 890 */ 134, 134, 133, 133, 132, 132, 132, 131, 128, 451, - /* 900 */ 1659, 399, 1169, 307, 893, 307, 515, 576, 413, 214, - /* 910 */ 498, 944, 1024, 540, 903, 1169, 943, 392, 1169, 1028, - /* 920 */ 1028, 1030, 406, 298, 1204, 50, 1149, 1658, 413, 1658, - /* 930 */ 145, 145, 137, 138, 91, 293, 1228, 1228, 1063, 1066, - /* 940 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 1188, 1147, - /* 950 */ 514, 1568, 137, 138, 91, 1505, 1228, 1228, 1063, 1066, - /* 960 */ 1053, 1053, 135, 135, 136, 136, 136, 136, 434, 323, - /* 970 */ 435, 539, 111, 1506, 274, 291, 372, 517, 367, 516, - /* 980 */ 262, 1204, 1205, 1204, 1574, 481, 363, 576, 7, 1569, - /* 990 */ 1568, 377, 134, 134, 134, 134, 133, 133, 132, 132, - /* 1000 */ 132, 131, 128, 451, 1568, 576, 1147, 576, 232, 576, - /* 1010 */ 19, 19, 134, 134, 134, 134, 133, 133, 132, 132, - /* 1020 */ 132, 131, 128, 451, 1169, 433, 576, 1207, 19, 19, - /* 1030 */ 19, 19, 19, 19, 1627, 576, 911, 1169, 47, 120, - /* 1040 */ 1169, 117, 413, 306, 498, 438, 1125, 206, 336, 19, - /* 1050 */ 19, 1435, 49, 449, 449, 449, 1368, 315, 81, 81, - /* 1060 */ 576, 304, 413, 1570, 207, 377, 137, 138, 91, 115, - /* 1070 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 1080 */ 136, 136, 576, 82, 82, 1207, 137, 138, 91, 1340, - /* 1090 */ 1228, 1228, 1063, 1066, 1053, 1053, 135, 135, 136, 136, - /* 1100 */ 136, 136, 1569, 386, 377, 82, 82, 463, 1126, 1552, - /* 1110 */ 333, 463, 335, 131, 128, 451, 1569, 161, 377, 16, - /* 1120 */ 317, 387, 428, 1127, 448, 447, 134, 134, 134, 134, - /* 1130 */ 133, 133, 132, 132, 132, 131, 128, 451, 1128, 576, - /* 1140 */ 1105, 10, 445, 267, 576, 1554, 134, 134, 134, 134, - /* 1150 */ 133, 133, 132, 132, 132, 131, 128, 451, 532, 576, - /* 1160 */ 922, 576, 19, 19, 576, 1573, 576, 147, 147, 7, - /* 1170 */ 923, 1236, 498, 1236, 576, 487, 413, 552, 285, 1224, - /* 1180 */ 969, 215, 82, 82, 66, 66, 1435, 67, 67, 21, - /* 1190 */ 21, 1110, 1110, 495, 334, 297, 413, 53, 53, 297, - /* 1200 */ 137, 138, 91, 119, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1210 */ 135, 135, 136, 136, 136, 136, 413, 1336, 1311, 446, - /* 1220 */ 137, 138, 91, 227, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1230 */ 135, 135, 136, 136, 136, 136, 574, 1224, 936, 936, - /* 1240 */ 137, 126, 91, 141, 1228, 1228, 1063, 1066, 1053, 1053, - /* 1250 */ 135, 135, 136, 136, 136, 136, 533, 429, 472, 346, - /* 1260 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1270 */ 128, 451, 576, 457, 233, 343, 1435, 403, 498, 1550, - /* 1280 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1290 */ 128, 451, 576, 324, 576, 82, 82, 487, 576, 969, - /* 1300 */ 134, 134, 134, 134, 133, 133, 132, 132, 132, 131, - /* 1310 */ 128, 451, 288, 288, 546, 68, 68, 54, 54, 553, - /* 1320 */ 413, 69, 69, 351, 6, 573, 944, 562, 410, 409, - /* 1330 */ 1435, 943, 450, 545, 260, 259, 258, 576, 158, 576, - /* 1340 */ 413, 222, 1180, 479, 969, 138, 91, 430, 1228, 1228, - /* 1350 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 1360 */ 70, 70, 71, 71, 576, 1126, 91, 576, 1228, 1228, - /* 1370 */ 1063, 1066, 1053, 1053, 135, 135, 136, 136, 136, 136, - /* 1380 */ 1127, 166, 850, 851, 852, 1282, 419, 72, 72, 108, - /* 1390 */ 73, 73, 1310, 358, 1180, 1128, 576, 305, 576, 123, - /* 1400 */ 568, 494, 4, 488, 134, 134, 134, 134, 133, 133, - /* 1410 */ 132, 132, 132, 131, 128, 451, 571, 564, 534, 55, - /* 1420 */ 55, 56, 56, 576, 134, 134, 134, 134, 133, 133, - /* 1430 */ 132, 132, 132, 131, 128, 451, 576, 1104, 233, 1104, - /* 1440 */ 452, 1602, 582, 2, 1259, 576, 57, 57, 576, 321, - /* 1450 */ 576, 155, 565, 1435, 485, 353, 576, 356, 1341, 59, - /* 1460 */ 59, 576, 44, 969, 569, 419, 576, 238, 60, 60, - /* 1470 */ 261, 74, 74, 75, 75, 287, 231, 576, 1366, 76, - /* 1480 */ 76, 1040, 420, 184, 20, 20, 576, 121, 121, 77, - /* 1490 */ 77, 97, 218, 288, 288, 122, 125, 452, 577, 452, - /* 1500 */ 143, 143, 1028, 576, 520, 576, 573, 576, 562, 144, - /* 1510 */ 144, 474, 227, 1244, 478, 123, 568, 576, 4, 320, - /* 1520 */ 567, 245, 411, 576, 443, 411, 78, 78, 62, 62, - /* 1530 */ 79, 79, 571, 319, 1028, 1028, 1030, 1031, 35, 418, - /* 1540 */ 63, 63, 576, 290, 411, 9, 80, 80, 1144, 576, - /* 1550 */ 400, 576, 486, 455, 576, 1223, 452, 576, 325, 342, - /* 1560 */ 576, 111, 576, 1188, 242, 64, 64, 473, 565, 576, - /* 1570 */ 23, 576, 170, 170, 171, 171, 576, 87, 87, 328, - /* 1580 */ 65, 65, 542, 83, 83, 146, 146, 541, 123, 568, - /* 1590 */ 341, 4, 84, 84, 168, 168, 576, 1040, 576, 148, - /* 1600 */ 148, 576, 1380, 121, 121, 571, 1021, 576, 266, 576, - /* 1610 */ 424, 122, 576, 452, 577, 452, 576, 553, 1028, 142, - /* 1620 */ 142, 169, 169, 576, 162, 162, 528, 889, 371, 452, - /* 1630 */ 152, 152, 151, 151, 1379, 149, 149, 109, 370, 150, - /* 1640 */ 150, 565, 576, 480, 576, 266, 86, 86, 576, 1092, - /* 1650 */ 1028, 1028, 1030, 1031, 35, 542, 482, 576, 266, 466, - /* 1660 */ 543, 123, 568, 1616, 4, 88, 88, 85, 85, 475, - /* 1670 */ 1040, 52, 52, 222, 901, 900, 121, 121, 571, 1188, - /* 1680 */ 58, 58, 244, 1032, 122, 889, 452, 577, 452, 908, - /* 1690 */ 909, 1028, 300, 347, 504, 111, 263, 361, 165, 111, - /* 1700 */ 111, 1088, 452, 263, 974, 1153, 266, 1092, 986, 987, - /* 1710 */ 942, 939, 125, 125, 565, 1103, 872, 1103, 159, 941, - /* 1720 */ 1309, 125, 1557, 1028, 1028, 1030, 1031, 35, 542, 337, - /* 1730 */ 1530, 205, 1529, 541, 499, 1589, 490, 348, 1376, 352, - /* 1740 */ 355, 1032, 357, 1040, 359, 1324, 1308, 366, 563, 121, - /* 1750 */ 121, 376, 1188, 1389, 1434, 1362, 280, 122, 1374, 452, - /* 1760 */ 577, 452, 167, 1439, 1028, 1289, 1280, 1268, 1267, 1269, - /* 1770 */ 1609, 1359, 312, 313, 314, 397, 12, 237, 224, 1421, - /* 1780 */ 295, 1416, 1409, 1426, 339, 484, 340, 509, 1371, 1612, - /* 1790 */ 1372, 1425, 1244, 404, 301, 228, 1028, 1028, 1030, 1031, - /* 1800 */ 35, 1601, 1192, 454, 345, 1307, 292, 369, 1502, 1501, - /* 1810 */ 270, 396, 396, 395, 277, 393, 1370, 1369, 859, 1549, - /* 1820 */ 186, 123, 568, 235, 4, 1188, 391, 210, 211, 223, - /* 1830 */ 1547, 239, 1241, 327, 422, 96, 220, 195, 571, 180, - /* 1840 */ 188, 326, 468, 469, 190, 191, 502, 192, 193, 566, - /* 1850 */ 247, 109, 1430, 491, 199, 251, 102, 281, 402, 476, - /* 1860 */ 405, 1496, 452, 497, 253, 1422, 13, 1428, 14, 1427, - /* 1870 */ 203, 1507, 241, 500, 565, 354, 407, 92, 95, 1270, - /* 1880 */ 175, 254, 518, 43, 1327, 255, 1326, 1325, 436, 1518, - /* 1890 */ 350, 1318, 104, 229, 893, 1626, 440, 441, 1625, 408, - /* 1900 */ 240, 1296, 268, 1040, 310, 269, 1297, 527, 444, 121, - /* 1910 */ 121, 368, 1295, 1594, 1624, 311, 1394, 122, 1317, 452, - /* 1920 */ 577, 452, 374, 1580, 1028, 1393, 140, 553, 11, 90, - /* 1930 */ 568, 385, 4, 116, 318, 414, 1579, 110, 1483, 537, - /* 1940 */ 320, 567, 1350, 555, 42, 579, 571, 1349, 1198, 383, - /* 1950 */ 276, 390, 216, 389, 278, 279, 1028, 1028, 1030, 1031, - /* 1960 */ 35, 172, 580, 1265, 458, 1260, 415, 416, 185, 156, - /* 1970 */ 452, 1534, 1535, 173, 1533, 1532, 89, 308, 225, 226, - /* 1980 */ 846, 174, 565, 453, 217, 1188, 322, 236, 1102, 154, - /* 1990 */ 1100, 330, 187, 176, 1223, 243, 189, 925, 338, 246, - /* 2000 */ 1116, 194, 177, 425, 178, 427, 98, 196, 99, 100, - /* 2010 */ 101, 1040, 179, 1119, 1115, 248, 249, 121, 121, 163, - /* 2020 */ 24, 250, 349, 1238, 496, 122, 1108, 452, 577, 452, - /* 2030 */ 1192, 454, 1028, 266, 292, 200, 252, 201, 861, 396, - /* 2040 */ 396, 395, 277, 393, 15, 501, 859, 370, 292, 256, - /* 2050 */ 202, 554, 505, 396, 396, 395, 277, 393, 103, 239, - /* 2060 */ 859, 327, 25, 26, 1028, 1028, 1030, 1031, 35, 326, - /* 2070 */ 362, 510, 891, 239, 365, 327, 513, 904, 105, 309, - /* 2080 */ 164, 181, 27, 326, 106, 521, 107, 1185, 1069, 1155, - /* 2090 */ 17, 1154, 230, 1188, 284, 286, 265, 204, 125, 1171, - /* 2100 */ 241, 28, 978, 972, 29, 41, 1175, 1179, 175, 1173, - /* 2110 */ 30, 43, 31, 8, 241, 1178, 32, 1160, 208, 549, - /* 2120 */ 33, 111, 175, 1083, 1070, 43, 1068, 1072, 240, 113, - /* 2130 */ 114, 34, 561, 118, 1124, 271, 1073, 36, 18, 572, - /* 2140 */ 1033, 873, 240, 124, 37, 935, 272, 273, 1617, 183, - /* 2150 */ 153, 394, 1194, 1193, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2160 */ 1256, 1256, 1256, 414, 1256, 1256, 1256, 1256, 320, 567, - /* 2170 */ 1256, 1256, 1256, 1256, 1256, 1256, 1256, 414, 1256, 1256, - /* 2180 */ 1256, 1256, 320, 567, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2190 */ 1256, 1256, 458, 1256, 1256, 1256, 1256, 1256, 1256, 1256, - /* 2200 */ 1256, 1256, 1256, 1256, 1256, 1256, 458, + /* 0 */ 134, 131, 238, 290, 290, 1353, 593, 1332, 478, 1606, + /* 10 */ 593, 1315, 593, 7, 593, 1353, 590, 593, 579, 424, + /* 20 */ 1566, 134, 131, 238, 1318, 541, 478, 477, 575, 84, + /* 30 */ 84, 1005, 303, 84, 84, 51, 51, 63, 63, 1006, + /* 40 */ 84, 84, 498, 141, 142, 93, 442, 1254, 1254, 1085, + /* 50 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 424, + /* 60 */ 296, 296, 498, 296, 296, 567, 553, 296, 296, 1306, + /* 70 */ 574, 1358, 1358, 590, 542, 579, 590, 574, 579, 548, + /* 80 */ 590, 1304, 579, 141, 142, 93, 576, 1254, 1254, 1085, + /* 90 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 399, + /* 100 */ 478, 395, 6, 138, 138, 138, 138, 137, 137, 136, + /* 110 */ 136, 136, 135, 132, 463, 44, 342, 593, 305, 1127, + /* 120 */ 1280, 1, 1, 599, 2, 1284, 598, 1200, 1284, 1200, + /* 130 */ 330, 424, 158, 330, 1613, 158, 390, 116, 308, 1366, + /* 140 */ 51, 51, 1366, 138, 138, 138, 138, 137, 137, 136, + /* 150 */ 136, 136, 135, 132, 463, 141, 142, 93, 515, 1254, + /* 160 */ 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, + /* 170 */ 140, 1230, 329, 584, 296, 296, 212, 296, 296, 568, + /* 180 */ 568, 488, 143, 1072, 1072, 1086, 1089, 590, 1195, 579, + /* 190 */ 590, 340, 579, 140, 140, 140, 140, 133, 392, 564, + /* 200 */ 536, 1195, 250, 425, 1195, 250, 137, 137, 136, 136, + /* 210 */ 136, 135, 132, 463, 291, 138, 138, 138, 138, 137, + /* 220 */ 137, 136, 136, 136, 135, 132, 463, 966, 1230, 1231, + /* 230 */ 1230, 412, 965, 467, 412, 424, 467, 489, 357, 1611, + /* 240 */ 391, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 250 */ 135, 132, 463, 463, 134, 131, 238, 555, 1076, 141, + /* 260 */ 142, 93, 593, 1254, 1254, 1085, 1088, 1075, 1075, 139, + /* 270 */ 139, 140, 140, 140, 140, 1317, 134, 131, 238, 424, + /* 280 */ 549, 1597, 1531, 333, 97, 83, 83, 140, 140, 140, + /* 290 */ 140, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 300 */ 135, 132, 463, 141, 142, 93, 1657, 1254, 1254, 1085, + /* 310 */ 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, 138, + /* 320 */ 138, 138, 138, 137, 137, 136, 136, 136, 135, 132, + /* 330 */ 463, 591, 1230, 958, 958, 138, 138, 138, 138, 137, + /* 340 */ 137, 136, 136, 136, 135, 132, 463, 44, 398, 547, + /* 350 */ 1306, 136, 136, 136, 135, 132, 463, 386, 593, 442, + /* 360 */ 595, 145, 595, 138, 138, 138, 138, 137, 137, 136, + /* 370 */ 136, 136, 135, 132, 463, 500, 1230, 112, 550, 460, + /* 380 */ 459, 51, 51, 424, 296, 296, 479, 334, 1259, 1230, + /* 390 */ 1231, 1230, 1599, 1261, 388, 312, 444, 590, 246, 579, + /* 400 */ 546, 1260, 271, 235, 329, 584, 551, 141, 142, 93, + /* 410 */ 429, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, + /* 420 */ 140, 140, 140, 22, 22, 1230, 1262, 424, 1262, 216, + /* 430 */ 296, 296, 98, 1230, 1231, 1230, 264, 884, 45, 528, + /* 440 */ 525, 524, 1041, 590, 1269, 579, 421, 420, 393, 523, + /* 450 */ 44, 141, 142, 93, 498, 1254, 1254, 1085, 1088, 1075, + /* 460 */ 1075, 139, 139, 140, 140, 140, 140, 138, 138, 138, + /* 470 */ 138, 137, 137, 136, 136, 136, 135, 132, 463, 593, + /* 480 */ 1611, 561, 1230, 1231, 1230, 23, 264, 515, 200, 528, + /* 490 */ 525, 524, 127, 585, 509, 4, 355, 487, 506, 523, + /* 500 */ 593, 498, 84, 84, 134, 131, 238, 329, 584, 588, + /* 510 */ 1627, 138, 138, 138, 138, 137, 137, 136, 136, 136, + /* 520 */ 135, 132, 463, 19, 19, 435, 1230, 1460, 297, 297, + /* 530 */ 311, 424, 1565, 464, 1631, 599, 2, 1284, 437, 574, + /* 540 */ 1107, 590, 330, 579, 158, 582, 489, 357, 573, 593, + /* 550 */ 592, 1366, 409, 1274, 1230, 141, 142, 93, 1364, 1254, + /* 560 */ 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, + /* 570 */ 140, 389, 84, 84, 1062, 567, 1230, 313, 1523, 593, + /* 580 */ 125, 125, 970, 1230, 1231, 1230, 296, 296, 126, 46, + /* 590 */ 464, 594, 464, 296, 296, 1050, 1230, 218, 439, 590, + /* 600 */ 1604, 579, 84, 84, 7, 403, 590, 515, 579, 325, + /* 610 */ 417, 1230, 1231, 1230, 250, 138, 138, 138, 138, 137, + /* 620 */ 137, 136, 136, 136, 135, 132, 463, 1050, 1050, 1052, + /* 630 */ 1053, 35, 1275, 1230, 1231, 1230, 424, 1370, 993, 574, + /* 640 */ 371, 414, 274, 412, 1597, 467, 1302, 552, 451, 590, + /* 650 */ 543, 579, 1530, 1230, 1231, 1230, 1214, 201, 409, 1174, + /* 660 */ 141, 142, 93, 223, 1254, 1254, 1085, 1088, 1075, 1075, + /* 670 */ 139, 139, 140, 140, 140, 140, 296, 296, 1250, 593, + /* 680 */ 424, 296, 296, 236, 529, 296, 296, 515, 100, 590, + /* 690 */ 1600, 579, 48, 1605, 590, 1230, 579, 7, 590, 577, + /* 700 */ 579, 904, 84, 84, 141, 142, 93, 496, 1254, 1254, + /* 710 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 720 */ 138, 138, 138, 138, 137, 137, 136, 136, 136, 135, + /* 730 */ 132, 463, 1365, 1230, 296, 296, 1250, 115, 1275, 326, + /* 740 */ 233, 539, 1062, 40, 282, 127, 585, 590, 4, 579, + /* 750 */ 329, 584, 1230, 1231, 1230, 1598, 593, 388, 904, 1051, + /* 760 */ 1356, 1356, 588, 1050, 138, 138, 138, 138, 137, 137, + /* 770 */ 136, 136, 136, 135, 132, 463, 185, 593, 1230, 19, + /* 780 */ 19, 1230, 971, 1597, 424, 1651, 464, 129, 908, 1195, + /* 790 */ 1230, 1231, 1230, 1325, 443, 1050, 1050, 1052, 582, 1603, + /* 800 */ 149, 149, 1195, 7, 5, 1195, 1687, 410, 141, 142, + /* 810 */ 93, 1536, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 820 */ 140, 140, 140, 140, 1214, 397, 593, 1062, 424, 1536, + /* 830 */ 1538, 50, 901, 125, 125, 1230, 1231, 1230, 1230, 1231, + /* 840 */ 1230, 126, 1230, 464, 594, 464, 515, 1230, 1050, 84, + /* 850 */ 84, 3, 141, 142, 93, 924, 1254, 1254, 1085, 1088, + /* 860 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 138, 138, + /* 870 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 880 */ 1050, 1050, 1052, 1053, 35, 442, 457, 532, 433, 1230, + /* 890 */ 1062, 1361, 540, 540, 1598, 925, 388, 7, 1129, 1230, + /* 900 */ 1231, 1230, 1129, 1536, 1230, 1231, 1230, 1051, 570, 1214, + /* 910 */ 593, 1050, 138, 138, 138, 138, 137, 137, 136, 136, + /* 920 */ 136, 135, 132, 463, 6, 185, 1195, 1230, 231, 593, + /* 930 */ 382, 992, 424, 151, 151, 510, 1213, 557, 482, 1195, + /* 940 */ 381, 160, 1195, 1050, 1050, 1052, 1230, 1231, 1230, 422, + /* 950 */ 593, 447, 84, 84, 593, 217, 141, 142, 93, 593, + /* 960 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 970 */ 140, 140, 1214, 19, 19, 593, 424, 19, 19, 442, + /* 980 */ 1063, 442, 19, 19, 1230, 1231, 1230, 515, 445, 458, + /* 990 */ 1597, 386, 315, 1175, 1685, 556, 1685, 450, 84, 84, + /* 1000 */ 141, 142, 93, 505, 1254, 1254, 1085, 1088, 1075, 1075, + /* 1010 */ 139, 139, 140, 140, 140, 140, 138, 138, 138, 138, + /* 1020 */ 137, 137, 136, 136, 136, 135, 132, 463, 442, 1147, + /* 1030 */ 454, 1597, 362, 1041, 593, 462, 1460, 1233, 47, 1393, + /* 1040 */ 324, 565, 565, 115, 1148, 449, 7, 460, 459, 307, + /* 1050 */ 375, 354, 593, 113, 593, 329, 584, 19, 19, 1149, + /* 1060 */ 138, 138, 138, 138, 137, 137, 136, 136, 136, 135, + /* 1070 */ 132, 463, 209, 1173, 563, 19, 19, 19, 19, 49, + /* 1080 */ 424, 944, 1175, 1686, 1046, 1686, 218, 355, 484, 343, + /* 1090 */ 210, 945, 569, 562, 1262, 1233, 1262, 490, 314, 423, + /* 1100 */ 424, 1598, 1206, 388, 141, 142, 93, 440, 1254, 1254, + /* 1110 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 1120 */ 352, 316, 531, 316, 141, 142, 93, 549, 1254, 1254, + /* 1130 */ 1085, 1088, 1075, 1075, 139, 139, 140, 140, 140, 140, + /* 1140 */ 446, 10, 1598, 274, 388, 915, 281, 299, 383, 534, + /* 1150 */ 378, 533, 269, 593, 1206, 587, 587, 587, 374, 293, + /* 1160 */ 1579, 991, 1173, 302, 138, 138, 138, 138, 137, 137, + /* 1170 */ 136, 136, 136, 135, 132, 463, 53, 53, 520, 1250, + /* 1180 */ 593, 1147, 1576, 431, 138, 138, 138, 138, 137, 137, + /* 1190 */ 136, 136, 136, 135, 132, 463, 1148, 301, 593, 1577, + /* 1200 */ 593, 1307, 431, 54, 54, 593, 268, 593, 461, 461, + /* 1210 */ 461, 1149, 347, 492, 424, 135, 132, 463, 1146, 1195, + /* 1220 */ 474, 68, 68, 69, 69, 550, 332, 287, 21, 21, + /* 1230 */ 55, 55, 1195, 581, 424, 1195, 309, 1250, 141, 142, + /* 1240 */ 93, 119, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 1250 */ 140, 140, 140, 140, 593, 237, 480, 1476, 141, 142, + /* 1260 */ 93, 593, 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, + /* 1270 */ 140, 140, 140, 140, 344, 430, 346, 70, 70, 494, + /* 1280 */ 991, 1132, 1132, 512, 56, 56, 1269, 593, 268, 593, + /* 1290 */ 369, 374, 593, 481, 215, 384, 1624, 481, 138, 138, + /* 1300 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 1310 */ 71, 71, 72, 72, 225, 73, 73, 593, 138, 138, + /* 1320 */ 138, 138, 137, 137, 136, 136, 136, 135, 132, 463, + /* 1330 */ 586, 431, 593, 872, 873, 874, 593, 911, 593, 1602, + /* 1340 */ 74, 74, 593, 7, 1460, 242, 593, 306, 424, 1578, + /* 1350 */ 472, 306, 364, 219, 367, 75, 75, 430, 345, 57, + /* 1360 */ 57, 58, 58, 432, 187, 59, 59, 593, 424, 61, + /* 1370 */ 61, 1475, 141, 142, 93, 123, 1254, 1254, 1085, 1088, + /* 1380 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 424, 570, + /* 1390 */ 62, 62, 141, 142, 93, 911, 1254, 1254, 1085, 1088, + /* 1400 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 161, 384, + /* 1410 */ 1624, 1474, 141, 130, 93, 441, 1254, 1254, 1085, 1088, + /* 1420 */ 1075, 1075, 139, 139, 140, 140, 140, 140, 267, 266, + /* 1430 */ 265, 1460, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1440 */ 136, 135, 132, 463, 593, 1336, 593, 1269, 1460, 384, + /* 1450 */ 1624, 231, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1460 */ 136, 135, 132, 463, 593, 163, 593, 76, 76, 77, + /* 1470 */ 77, 593, 138, 138, 138, 138, 137, 137, 136, 136, + /* 1480 */ 136, 135, 132, 463, 475, 593, 483, 78, 78, 20, + /* 1490 */ 20, 1249, 424, 491, 79, 79, 495, 422, 295, 235, + /* 1500 */ 1574, 38, 511, 896, 422, 335, 240, 422, 147, 147, + /* 1510 */ 112, 593, 424, 593, 101, 222, 991, 142, 93, 455, + /* 1520 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 1530 */ 140, 140, 593, 39, 148, 148, 80, 80, 93, 551, + /* 1540 */ 1254, 1254, 1085, 1088, 1075, 1075, 139, 139, 140, 140, + /* 1550 */ 140, 140, 328, 923, 922, 64, 64, 502, 1656, 1005, + /* 1560 */ 933, 896, 124, 422, 121, 254, 593, 1006, 593, 226, + /* 1570 */ 593, 127, 585, 164, 4, 16, 138, 138, 138, 138, + /* 1580 */ 137, 137, 136, 136, 136, 135, 132, 463, 588, 81, + /* 1590 */ 81, 65, 65, 82, 82, 593, 138, 138, 138, 138, + /* 1600 */ 137, 137, 136, 136, 136, 135, 132, 463, 593, 226, + /* 1610 */ 237, 966, 464, 593, 298, 593, 965, 593, 66, 66, + /* 1620 */ 593, 1170, 593, 411, 582, 353, 469, 115, 593, 471, + /* 1630 */ 169, 173, 173, 593, 44, 991, 174, 174, 89, 89, + /* 1640 */ 67, 67, 593, 85, 85, 150, 150, 1114, 1043, 593, + /* 1650 */ 273, 86, 86, 1062, 593, 503, 171, 171, 593, 125, + /* 1660 */ 125, 497, 593, 273, 336, 152, 152, 126, 1335, 464, + /* 1670 */ 594, 464, 146, 146, 1050, 593, 545, 172, 172, 593, + /* 1680 */ 1054, 165, 165, 256, 339, 156, 156, 127, 585, 1586, + /* 1690 */ 4, 329, 584, 499, 358, 273, 115, 348, 155, 155, + /* 1700 */ 930, 931, 153, 153, 588, 1114, 1050, 1050, 1052, 1053, + /* 1710 */ 35, 1554, 521, 593, 270, 1008, 1009, 9, 593, 372, + /* 1720 */ 593, 115, 593, 168, 593, 115, 593, 1110, 464, 270, + /* 1730 */ 996, 964, 273, 129, 1645, 1214, 154, 154, 1054, 1404, + /* 1740 */ 582, 88, 88, 90, 90, 87, 87, 52, 52, 60, + /* 1750 */ 60, 1405, 504, 537, 559, 1179, 961, 507, 129, 558, + /* 1760 */ 127, 585, 1126, 4, 1126, 1125, 894, 1125, 162, 1062, + /* 1770 */ 963, 359, 129, 1401, 363, 125, 125, 588, 366, 368, + /* 1780 */ 370, 1349, 1334, 126, 1333, 464, 594, 464, 377, 387, + /* 1790 */ 1050, 1391, 1414, 1618, 1459, 1387, 1399, 208, 580, 1464, + /* 1800 */ 1314, 464, 243, 516, 1305, 1293, 1384, 1292, 1294, 1638, + /* 1810 */ 288, 170, 228, 582, 12, 408, 321, 322, 241, 323, + /* 1820 */ 245, 1446, 1050, 1050, 1052, 1053, 35, 559, 304, 350, + /* 1830 */ 351, 501, 560, 127, 585, 1441, 4, 1451, 1434, 310, + /* 1840 */ 1450, 526, 1062, 1332, 415, 380, 232, 1527, 125, 125, + /* 1850 */ 588, 1214, 1396, 356, 1526, 583, 126, 1397, 464, 594, + /* 1860 */ 464, 1641, 535, 1050, 1581, 1395, 1269, 1583, 1582, 213, + /* 1870 */ 402, 277, 214, 227, 464, 1573, 239, 1571, 1266, 1394, + /* 1880 */ 434, 198, 100, 224, 96, 183, 582, 191, 485, 193, + /* 1890 */ 486, 194, 195, 196, 519, 1050, 1050, 1052, 1053, 35, + /* 1900 */ 559, 113, 252, 413, 1447, 558, 493, 13, 1455, 416, + /* 1910 */ 1453, 1452, 14, 202, 1521, 1062, 1532, 508, 258, 106, + /* 1920 */ 514, 125, 125, 99, 1214, 1543, 289, 260, 206, 126, + /* 1930 */ 365, 464, 594, 464, 361, 517, 1050, 261, 448, 1295, + /* 1940 */ 262, 418, 1352, 1351, 108, 1350, 1655, 1654, 1343, 915, + /* 1950 */ 419, 1322, 233, 452, 319, 379, 1321, 453, 1623, 320, + /* 1960 */ 1320, 275, 1653, 544, 276, 1609, 1608, 1342, 1050, 1050, + /* 1970 */ 1052, 1053, 35, 1630, 1218, 466, 385, 456, 300, 1419, + /* 1980 */ 144, 1418, 570, 407, 407, 406, 284, 404, 11, 1508, + /* 1990 */ 881, 396, 120, 127, 585, 394, 4, 1214, 327, 114, + /* 2000 */ 1375, 1374, 220, 247, 400, 338, 401, 554, 42, 1224, + /* 2010 */ 588, 596, 283, 337, 285, 286, 188, 597, 1290, 1285, + /* 2020 */ 175, 1558, 176, 1559, 1557, 1556, 159, 317, 229, 177, + /* 2030 */ 868, 230, 91, 465, 464, 221, 331, 468, 1165, 470, + /* 2040 */ 473, 94, 244, 95, 249, 189, 582, 1124, 1122, 341, + /* 2050 */ 427, 190, 178, 1249, 179, 43, 192, 947, 349, 428, + /* 2060 */ 1138, 197, 251, 180, 181, 436, 102, 182, 438, 103, + /* 2070 */ 104, 199, 248, 1140, 253, 1062, 105, 255, 1137, 166, + /* 2080 */ 24, 125, 125, 257, 1264, 273, 360, 513, 259, 126, + /* 2090 */ 15, 464, 594, 464, 204, 883, 1050, 518, 263, 373, + /* 2100 */ 381, 92, 585, 1130, 4, 203, 205, 426, 107, 522, + /* 2110 */ 25, 26, 329, 584, 913, 572, 527, 376, 588, 926, + /* 2120 */ 530, 109, 184, 318, 167, 110, 27, 538, 1050, 1050, + /* 2130 */ 1052, 1053, 35, 1211, 1091, 17, 476, 111, 1181, 234, + /* 2140 */ 292, 1180, 464, 294, 207, 994, 129, 1201, 272, 1000, + /* 2150 */ 28, 1197, 29, 30, 582, 1199, 1205, 1214, 31, 1204, + /* 2160 */ 32, 1186, 41, 566, 33, 1105, 211, 8, 115, 1092, + /* 2170 */ 1090, 1094, 34, 278, 578, 1095, 117, 122, 118, 1145, + /* 2180 */ 36, 18, 128, 1062, 1055, 895, 957, 37, 589, 125, + /* 2190 */ 125, 279, 186, 280, 1646, 157, 405, 126, 1220, 464, + /* 2200 */ 594, 464, 1218, 466, 1050, 1219, 300, 1281, 1281, 1281, + /* 2210 */ 1281, 407, 407, 406, 284, 404, 1281, 1281, 881, 1281, + /* 2220 */ 300, 1281, 1281, 571, 1281, 407, 407, 406, 284, 404, + /* 2230 */ 1281, 247, 881, 338, 1281, 1281, 1050, 1050, 1052, 1053, + /* 2240 */ 35, 337, 1281, 1281, 1281, 247, 1281, 338, 1281, 1281, + /* 2250 */ 1281, 1281, 1281, 1281, 1281, 337, 1281, 1281, 1281, 1281, + /* 2260 */ 1281, 1281, 1281, 1281, 1281, 1214, 1281, 1281, 1281, 1281, + /* 2270 */ 1281, 1281, 249, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2280 */ 178, 1281, 1281, 43, 1281, 1281, 249, 1281, 1281, 1281, + /* 2290 */ 1281, 1281, 1281, 1281, 178, 1281, 1281, 43, 1281, 1281, + /* 2300 */ 248, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2310 */ 1281, 1281, 1281, 1281, 248, 1281, 1281, 1281, 1281, 1281, + /* 2320 */ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, + /* 2330 */ 1281, 1281, 1281, 1281, 1281, 426, 1281, 1281, 1281, 1281, + /* 2340 */ 329, 584, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 426, + /* 2350 */ 1281, 1281, 1281, 1281, 329, 584, 1281, 1281, 1281, 1281, + /* 2360 */ 1281, 1281, 1281, 1281, 476, 1281, 1281, 1281, 1281, 1281, + /* 2370 */ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 476, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 277, 278, 279, 241, 242, 225, 195, 227, 195, 241, - /* 10 */ 242, 195, 217, 221, 195, 235, 254, 195, 256, 19, - /* 20 */ 225, 298, 254, 195, 256, 206, 213, 214, 206, 218, - /* 30 */ 219, 31, 206, 195, 218, 219, 195, 218, 219, 39, - /* 40 */ 218, 219, 313, 43, 44, 45, 317, 47, 48, 49, + /* 0 */ 277, 278, 279, 241, 242, 225, 195, 227, 195, 312, + /* 10 */ 195, 218, 195, 316, 195, 235, 254, 195, 256, 19, + /* 20 */ 297, 277, 278, 279, 218, 206, 213, 214, 206, 218, + /* 30 */ 219, 31, 206, 218, 219, 218, 219, 218, 219, 39, + /* 40 */ 218, 219, 195, 43, 44, 45, 195, 47, 48, 49, /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 19, - /* 60 */ 241, 242, 195, 241, 242, 195, 255, 241, 242, 277, - /* 70 */ 278, 279, 234, 254, 255, 256, 254, 255, 256, 218, - /* 80 */ 254, 240, 256, 43, 44, 45, 264, 47, 48, 49, - /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 271, - /* 100 */ 287, 22, 23, 103, 104, 105, 106, 107, 108, 109, - /* 110 */ 110, 111, 112, 113, 114, 114, 47, 48, 49, 50, + /* 60 */ 241, 242, 195, 241, 242, 195, 255, 241, 242, 195, + /* 70 */ 255, 237, 238, 254, 255, 256, 254, 255, 256, 264, + /* 80 */ 254, 207, 256, 43, 44, 45, 264, 47, 48, 49, + /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 251, + /* 100 */ 287, 253, 215, 103, 104, 105, 106, 107, 108, 109, + /* 110 */ 110, 111, 112, 113, 114, 82, 265, 195, 271, 11, /* 120 */ 187, 188, 189, 190, 191, 192, 190, 87, 192, 89, - /* 130 */ 197, 19, 199, 197, 318, 199, 320, 25, 195, 206, - /* 140 */ 299, 271, 206, 103, 104, 105, 106, 107, 108, 109, + /* 130 */ 197, 19, 199, 197, 317, 199, 319, 25, 271, 206, + /* 140 */ 218, 219, 206, 103, 104, 105, 106, 107, 108, 109, /* 150 */ 110, 111, 112, 113, 114, 43, 44, 45, 195, 47, /* 160 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - /* 170 */ 58, 60, 21, 195, 241, 242, 215, 241, 242, 312, - /* 180 */ 313, 102, 70, 205, 317, 207, 242, 254, 77, 256, - /* 190 */ 254, 122, 256, 55, 56, 57, 58, 59, 254, 88, - /* 200 */ 256, 90, 269, 240, 93, 269, 107, 108, 109, 110, - /* 210 */ 111, 112, 113, 114, 271, 103, 104, 105, 106, 107, - /* 220 */ 108, 109, 110, 111, 112, 113, 114, 313, 117, 118, - /* 230 */ 119, 317, 81, 195, 301, 19, 195, 301, 277, 278, - /* 240 */ 279, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 250 */ 112, 113, 114, 55, 56, 57, 58, 146, 195, 43, - /* 260 */ 44, 45, 74, 47, 48, 49, 50, 51, 52, 53, - /* 270 */ 54, 55, 56, 57, 58, 124, 195, 60, 109, 110, - /* 280 */ 111, 112, 113, 114, 68, 195, 103, 104, 105, 106, - /* 290 */ 107, 108, 109, 110, 111, 112, 113, 114, 208, 218, - /* 300 */ 219, 103, 104, 105, 106, 107, 108, 109, 110, 111, - /* 310 */ 112, 113, 114, 162, 233, 24, 128, 129, 130, 103, + /* 170 */ 58, 60, 139, 140, 241, 242, 289, 241, 242, 309, + /* 180 */ 310, 294, 70, 47, 48, 49, 50, 254, 77, 256, + /* 190 */ 254, 195, 256, 55, 56, 57, 58, 59, 221, 88, + /* 200 */ 109, 90, 269, 240, 93, 269, 107, 108, 109, 110, + /* 210 */ 111, 112, 113, 114, 215, 103, 104, 105, 106, 107, + /* 220 */ 108, 109, 110, 111, 112, 113, 114, 136, 117, 118, + /* 230 */ 119, 298, 141, 300, 298, 19, 300, 129, 130, 317, + /* 240 */ 318, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 250 */ 112, 113, 114, 114, 277, 278, 279, 146, 122, 43, + /* 260 */ 44, 45, 195, 47, 48, 49, 50, 51, 52, 53, + /* 270 */ 54, 55, 56, 57, 58, 218, 277, 278, 279, 19, + /* 280 */ 19, 195, 286, 23, 68, 218, 219, 55, 56, 57, + /* 290 */ 58, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 300 */ 112, 113, 114, 43, 44, 45, 232, 47, 48, 49, + /* 310 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 103, /* 320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - /* 330 */ 114, 195, 195, 215, 117, 118, 119, 120, 195, 19, - /* 340 */ 123, 124, 125, 207, 24, 74, 246, 60, 310, 311, - /* 350 */ 133, 60, 311, 82, 22, 218, 219, 257, 195, 19, - /* 360 */ 73, 218, 219, 43, 44, 45, 206, 47, 48, 49, - /* 370 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 22, - /* 380 */ 23, 218, 219, 43, 44, 45, 54, 47, 48, 49, - /* 390 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 128, - /* 400 */ 82, 241, 242, 195, 117, 118, 119, 289, 60, 118, - /* 410 */ 139, 140, 294, 195, 254, 195, 256, 195, 255, 259, - /* 420 */ 260, 73, 22, 103, 104, 105, 106, 107, 108, 109, - /* 430 */ 110, 111, 112, 113, 114, 206, 218, 219, 218, 219, - /* 440 */ 218, 219, 234, 103, 104, 105, 106, 107, 108, 109, - /* 450 */ 110, 111, 112, 113, 114, 318, 319, 139, 140, 102, - /* 460 */ 60, 318, 319, 221, 19, 117, 118, 119, 23, 195, - /* 470 */ 241, 242, 313, 255, 206, 255, 317, 255, 206, 129, - /* 480 */ 130, 206, 264, 254, 264, 256, 264, 195, 43, 44, - /* 490 */ 45, 151, 47, 48, 49, 50, 51, 52, 53, 54, - /* 500 */ 55, 56, 57, 58, 246, 213, 214, 19, 19, 241, - /* 510 */ 242, 195, 23, 241, 242, 257, 241, 242, 118, 277, - /* 520 */ 278, 279, 254, 29, 256, 60, 254, 33, 256, 254, - /* 530 */ 206, 256, 43, 44, 45, 218, 47, 48, 49, 50, - /* 540 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104, - /* 550 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 560 */ 66, 19, 218, 60, 120, 241, 242, 123, 124, 125, - /* 570 */ 60, 232, 77, 19, 20, 26, 22, 133, 254, 287, - /* 580 */ 256, 265, 117, 118, 119, 90, 312, 313, 93, 47, - /* 590 */ 36, 317, 103, 104, 105, 106, 107, 108, 109, 110, - /* 600 */ 111, 112, 113, 114, 116, 117, 277, 278, 279, 60, - /* 610 */ 107, 108, 19, 276, 60, 31, 23, 152, 195, 116, - /* 620 */ 117, 118, 119, 39, 121, 276, 72, 117, 118, 119, - /* 630 */ 166, 167, 129, 145, 237, 238, 43, 44, 45, 276, - /* 640 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 650 */ 57, 58, 315, 316, 144, 101, 19, 154, 116, 156, - /* 660 */ 23, 107, 108, 109, 315, 316, 117, 118, 119, 115, - /* 670 */ 60, 117, 118, 119, 132, 200, 122, 60, 315, 316, - /* 680 */ 43, 44, 45, 272, 47, 48, 49, 50, 51, 52, - /* 690 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106, - /* 700 */ 107, 108, 109, 110, 111, 112, 113, 114, 154, 155, - /* 710 */ 156, 157, 158, 212, 213, 214, 22, 195, 101, 22, - /* 720 */ 60, 19, 20, 60, 22, 139, 140, 117, 118, 119, - /* 730 */ 22, 251, 195, 253, 117, 118, 195, 183, 36, 122, - /* 740 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 750 */ 113, 114, 195, 195, 60, 218, 219, 60, 195, 284, - /* 760 */ 19, 25, 60, 288, 23, 237, 238, 22, 60, 109, - /* 770 */ 233, 154, 155, 156, 72, 218, 219, 117, 118, 119, - /* 780 */ 117, 118, 119, 116, 43, 44, 45, 265, 47, 48, - /* 790 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 800 */ 183, 243, 25, 101, 19, 60, 265, 144, 23, 107, - /* 810 */ 108, 117, 118, 119, 117, 118, 119, 115, 151, 117, - /* 820 */ 118, 119, 82, 195, 122, 117, 118, 119, 43, 44, - /* 830 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54, - /* 840 */ 55, 56, 57, 58, 103, 104, 105, 106, 107, 108, - /* 850 */ 109, 110, 111, 112, 113, 114, 154, 155, 156, 157, - /* 860 */ 158, 121, 117, 118, 119, 307, 101, 309, 195, 22, - /* 870 */ 23, 195, 25, 19, 35, 139, 140, 195, 24, 139, - /* 880 */ 140, 208, 195, 118, 109, 183, 22, 122, 103, 104, - /* 890 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - /* 900 */ 304, 305, 77, 230, 127, 232, 67, 195, 19, 195, - /* 910 */ 195, 136, 23, 88, 75, 90, 141, 203, 93, 154, - /* 920 */ 155, 156, 208, 295, 60, 243, 22, 23, 19, 25, - /* 930 */ 218, 219, 43, 44, 45, 100, 47, 48, 49, 50, - /* 940 */ 51, 52, 53, 54, 55, 56, 57, 58, 183, 102, - /* 950 */ 96, 195, 43, 44, 45, 240, 47, 48, 49, 50, - /* 960 */ 51, 52, 53, 54, 55, 56, 57, 58, 114, 134, - /* 970 */ 131, 146, 25, 286, 120, 121, 122, 123, 124, 125, - /* 980 */ 126, 117, 118, 119, 313, 195, 132, 195, 317, 307, - /* 990 */ 195, 309, 103, 104, 105, 106, 107, 108, 109, 110, - /* 1000 */ 111, 112, 113, 114, 195, 195, 102, 195, 195, 195, - /* 1010 */ 218, 219, 103, 104, 105, 106, 107, 108, 109, 110, - /* 1020 */ 111, 112, 113, 114, 77, 233, 195, 60, 218, 219, - /* 1030 */ 218, 219, 218, 219, 23, 195, 25, 90, 243, 159, - /* 1040 */ 93, 161, 19, 233, 195, 233, 23, 233, 16, 218, - /* 1050 */ 219, 195, 243, 212, 213, 214, 262, 263, 218, 219, - /* 1060 */ 195, 271, 19, 307, 233, 309, 43, 44, 45, 160, - /* 1070 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1080 */ 57, 58, 195, 218, 219, 118, 43, 44, 45, 240, - /* 1090 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - /* 1100 */ 57, 58, 307, 195, 309, 218, 219, 263, 12, 195, - /* 1110 */ 78, 267, 80, 112, 113, 114, 307, 22, 309, 24, - /* 1120 */ 255, 281, 266, 27, 107, 108, 103, 104, 105, 106, - /* 1130 */ 107, 108, 109, 110, 111, 112, 113, 114, 42, 195, - /* 1140 */ 11, 22, 255, 24, 195, 195, 103, 104, 105, 106, - /* 1150 */ 107, 108, 109, 110, 111, 112, 113, 114, 19, 195, - /* 1160 */ 64, 195, 218, 219, 195, 313, 195, 218, 219, 317, - /* 1170 */ 74, 154, 195, 156, 195, 195, 19, 233, 23, 60, - /* 1180 */ 25, 24, 218, 219, 218, 219, 195, 218, 219, 218, - /* 1190 */ 219, 128, 129, 130, 162, 263, 19, 218, 219, 267, - /* 1200 */ 43, 44, 45, 160, 47, 48, 49, 50, 51, 52, - /* 1210 */ 53, 54, 55, 56, 57, 58, 19, 240, 228, 255, - /* 1220 */ 43, 44, 45, 25, 47, 48, 49, 50, 51, 52, - /* 1230 */ 53, 54, 55, 56, 57, 58, 135, 118, 137, 138, - /* 1240 */ 43, 44, 45, 22, 47, 48, 49, 50, 51, 52, - /* 1250 */ 53, 54, 55, 56, 57, 58, 117, 266, 129, 130, - /* 1260 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1270 */ 113, 114, 195, 195, 119, 295, 195, 206, 195, 195, - /* 1280 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1290 */ 113, 114, 195, 195, 195, 218, 219, 195, 195, 144, - /* 1300 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - /* 1310 */ 113, 114, 241, 242, 67, 218, 219, 218, 219, 146, - /* 1320 */ 19, 218, 219, 240, 215, 254, 136, 256, 107, 108, - /* 1330 */ 195, 141, 255, 86, 128, 129, 130, 195, 165, 195, - /* 1340 */ 19, 143, 95, 272, 25, 44, 45, 266, 47, 48, - /* 1350 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 1360 */ 218, 219, 218, 219, 195, 12, 45, 195, 47, 48, - /* 1370 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - /* 1380 */ 27, 23, 7, 8, 9, 210, 211, 218, 219, 116, - /* 1390 */ 218, 219, 228, 16, 147, 42, 195, 295, 195, 19, - /* 1400 */ 20, 266, 22, 294, 103, 104, 105, 106, 107, 108, - /* 1410 */ 109, 110, 111, 112, 113, 114, 36, 64, 145, 218, - /* 1420 */ 219, 218, 219, 195, 103, 104, 105, 106, 107, 108, - /* 1430 */ 109, 110, 111, 112, 113, 114, 195, 154, 119, 156, - /* 1440 */ 60, 189, 190, 191, 192, 195, 218, 219, 195, 197, - /* 1450 */ 195, 199, 72, 195, 19, 78, 195, 80, 206, 218, - /* 1460 */ 219, 195, 82, 144, 210, 211, 195, 15, 218, 219, - /* 1470 */ 47, 218, 219, 218, 219, 259, 260, 195, 261, 218, - /* 1480 */ 219, 101, 302, 303, 218, 219, 195, 107, 108, 218, - /* 1490 */ 219, 150, 151, 241, 242, 115, 25, 117, 118, 119, - /* 1500 */ 218, 219, 122, 195, 146, 195, 254, 195, 256, 218, - /* 1510 */ 219, 246, 25, 61, 246, 19, 20, 195, 22, 139, - /* 1520 */ 140, 269, 257, 195, 266, 257, 218, 219, 218, 219, - /* 1530 */ 218, 219, 36, 246, 154, 155, 156, 157, 158, 116, - /* 1540 */ 218, 219, 195, 22, 257, 49, 218, 219, 23, 195, - /* 1550 */ 25, 195, 117, 301, 195, 25, 60, 195, 195, 23, - /* 1560 */ 195, 25, 195, 183, 24, 218, 219, 130, 72, 195, - /* 1570 */ 22, 195, 218, 219, 218, 219, 195, 218, 219, 195, - /* 1580 */ 218, 219, 86, 218, 219, 218, 219, 91, 19, 20, - /* 1590 */ 153, 22, 218, 219, 218, 219, 195, 101, 195, 218, - /* 1600 */ 219, 195, 195, 107, 108, 36, 23, 195, 25, 195, - /* 1610 */ 62, 115, 195, 117, 118, 119, 195, 146, 122, 218, - /* 1620 */ 219, 218, 219, 195, 218, 219, 19, 60, 122, 60, - /* 1630 */ 218, 219, 218, 219, 195, 218, 219, 150, 132, 218, - /* 1640 */ 219, 72, 195, 23, 195, 25, 218, 219, 195, 60, - /* 1650 */ 154, 155, 156, 157, 158, 86, 23, 195, 25, 195, - /* 1660 */ 91, 19, 20, 142, 22, 218, 219, 218, 219, 130, - /* 1670 */ 101, 218, 219, 143, 121, 122, 107, 108, 36, 183, - /* 1680 */ 218, 219, 142, 60, 115, 118, 117, 118, 119, 7, - /* 1690 */ 8, 122, 153, 23, 23, 25, 25, 23, 23, 25, - /* 1700 */ 25, 23, 60, 25, 23, 98, 25, 118, 84, 85, - /* 1710 */ 23, 23, 25, 25, 72, 154, 23, 156, 25, 23, - /* 1720 */ 228, 25, 195, 154, 155, 156, 157, 158, 86, 195, - /* 1730 */ 195, 258, 195, 91, 291, 322, 195, 195, 195, 195, - /* 1740 */ 195, 118, 195, 101, 195, 195, 195, 195, 238, 107, - /* 1750 */ 108, 195, 183, 195, 195, 195, 290, 115, 195, 117, - /* 1760 */ 118, 119, 244, 195, 122, 195, 195, 195, 195, 195, - /* 1770 */ 195, 258, 258, 258, 258, 193, 245, 300, 216, 274, - /* 1780 */ 247, 270, 270, 274, 296, 296, 248, 222, 262, 198, - /* 1790 */ 262, 274, 61, 274, 248, 231, 154, 155, 156, 157, - /* 1800 */ 158, 0, 1, 2, 247, 227, 5, 221, 221, 221, - /* 1810 */ 142, 10, 11, 12, 13, 14, 262, 262, 17, 202, - /* 1820 */ 300, 19, 20, 300, 22, 183, 247, 251, 251, 245, - /* 1830 */ 202, 30, 38, 32, 202, 152, 151, 22, 36, 43, - /* 1840 */ 236, 40, 18, 202, 239, 239, 18, 239, 239, 283, - /* 1850 */ 201, 150, 236, 202, 236, 201, 159, 202, 248, 248, - /* 1860 */ 248, 248, 60, 63, 201, 275, 273, 275, 273, 275, - /* 1870 */ 22, 286, 71, 223, 72, 202, 223, 297, 297, 202, - /* 1880 */ 79, 201, 116, 82, 220, 201, 220, 220, 65, 293, - /* 1890 */ 292, 229, 22, 166, 127, 226, 24, 114, 226, 223, - /* 1900 */ 99, 222, 202, 101, 285, 92, 220, 308, 83, 107, - /* 1910 */ 108, 220, 220, 316, 220, 285, 268, 115, 229, 117, - /* 1920 */ 118, 119, 223, 321, 122, 268, 149, 146, 22, 19, - /* 1930 */ 20, 202, 22, 159, 282, 134, 321, 148, 280, 147, - /* 1940 */ 139, 140, 252, 141, 25, 204, 36, 252, 13, 251, - /* 1950 */ 196, 248, 250, 249, 196, 6, 154, 155, 156, 157, - /* 1960 */ 158, 209, 194, 194, 163, 194, 306, 306, 303, 224, - /* 1970 */ 60, 215, 215, 209, 215, 215, 215, 224, 216, 216, - /* 1980 */ 4, 209, 72, 3, 22, 183, 164, 15, 23, 16, - /* 1990 */ 23, 140, 152, 131, 25, 24, 143, 20, 16, 145, - /* 2000 */ 1, 143, 131, 62, 131, 37, 54, 152, 54, 54, - /* 2010 */ 54, 101, 131, 117, 1, 34, 142, 107, 108, 5, - /* 2020 */ 22, 116, 162, 76, 41, 115, 69, 117, 118, 119, - /* 2030 */ 1, 2, 122, 25, 5, 69, 142, 116, 20, 10, - /* 2040 */ 11, 12, 13, 14, 24, 19, 17, 132, 5, 126, - /* 2050 */ 22, 141, 68, 10, 11, 12, 13, 14, 22, 30, - /* 2060 */ 17, 32, 22, 22, 154, 155, 156, 157, 158, 40, - /* 2070 */ 23, 68, 60, 30, 24, 32, 97, 28, 22, 68, - /* 2080 */ 23, 37, 34, 40, 150, 22, 25, 23, 23, 23, - /* 2090 */ 22, 98, 142, 183, 23, 23, 34, 22, 25, 89, - /* 2100 */ 71, 34, 117, 144, 34, 22, 76, 76, 79, 87, - /* 2110 */ 34, 82, 34, 44, 71, 94, 34, 23, 25, 24, - /* 2120 */ 34, 25, 79, 23, 23, 82, 23, 23, 99, 143, - /* 2130 */ 143, 22, 25, 25, 23, 22, 11, 22, 22, 25, - /* 2140 */ 23, 23, 99, 22, 22, 136, 142, 142, 142, 25, - /* 2150 */ 23, 15, 1, 1, 323, 323, 323, 323, 323, 323, - /* 2160 */ 323, 323, 323, 134, 323, 323, 323, 323, 139, 140, - /* 2170 */ 323, 323, 323, 323, 323, 323, 323, 134, 323, 323, - /* 2180 */ 323, 323, 139, 140, 323, 323, 323, 323, 323, 323, - /* 2190 */ 323, 323, 163, 323, 323, 323, 323, 323, 323, 323, - /* 2200 */ 323, 323, 323, 323, 323, 323, 163, 323, 323, 323, - /* 2210 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2220 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2230 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2240 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2250 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2260 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2270 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2280 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2290 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2300 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2310 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2320 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2330 */ 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - /* 2340 */ 323, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2350 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2360 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2370 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2380 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, - /* 2390 */ 187, 187, 187, 187, + /* 330 */ 114, 135, 60, 137, 138, 103, 104, 105, 106, 107, + /* 340 */ 108, 109, 110, 111, 112, 113, 114, 82, 281, 206, + /* 350 */ 195, 109, 110, 111, 112, 113, 114, 195, 195, 195, + /* 360 */ 205, 22, 207, 103, 104, 105, 106, 107, 108, 109, + /* 370 */ 110, 111, 112, 113, 114, 195, 60, 116, 117, 107, + /* 380 */ 108, 218, 219, 19, 241, 242, 121, 23, 116, 117, + /* 390 */ 118, 119, 306, 121, 308, 206, 234, 254, 15, 256, + /* 400 */ 195, 129, 259, 260, 139, 140, 145, 43, 44, 45, + /* 410 */ 200, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 420 */ 56, 57, 58, 218, 219, 60, 154, 19, 156, 265, + /* 430 */ 241, 242, 24, 117, 118, 119, 120, 21, 73, 123, + /* 440 */ 124, 125, 74, 254, 61, 256, 107, 108, 221, 133, + /* 450 */ 82, 43, 44, 45, 195, 47, 48, 49, 50, 51, + /* 460 */ 52, 53, 54, 55, 56, 57, 58, 103, 104, 105, + /* 470 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 195, + /* 480 */ 317, 318, 117, 118, 119, 22, 120, 195, 22, 123, + /* 490 */ 124, 125, 19, 20, 284, 22, 128, 81, 288, 133, + /* 500 */ 195, 195, 218, 219, 277, 278, 279, 139, 140, 36, + /* 510 */ 195, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 520 */ 112, 113, 114, 218, 219, 62, 60, 195, 241, 242, + /* 530 */ 271, 19, 240, 60, 189, 190, 191, 192, 233, 255, + /* 540 */ 124, 254, 197, 256, 199, 72, 129, 130, 264, 195, + /* 550 */ 195, 206, 22, 23, 60, 43, 44, 45, 206, 47, + /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 570 */ 58, 195, 218, 219, 101, 195, 60, 271, 162, 195, + /* 580 */ 107, 108, 109, 117, 118, 119, 241, 242, 115, 73, + /* 590 */ 117, 118, 119, 241, 242, 122, 60, 195, 266, 254, + /* 600 */ 312, 256, 218, 219, 316, 203, 254, 195, 256, 255, + /* 610 */ 208, 117, 118, 119, 269, 103, 104, 105, 106, 107, + /* 620 */ 108, 109, 110, 111, 112, 113, 114, 154, 155, 156, + /* 630 */ 157, 158, 102, 117, 118, 119, 19, 242, 144, 255, + /* 640 */ 23, 206, 24, 298, 195, 300, 206, 195, 264, 254, + /* 650 */ 206, 256, 240, 117, 118, 119, 183, 22, 22, 23, + /* 660 */ 43, 44, 45, 151, 47, 48, 49, 50, 51, 52, + /* 670 */ 53, 54, 55, 56, 57, 58, 241, 242, 60, 195, + /* 680 */ 19, 241, 242, 195, 23, 241, 242, 195, 152, 254, + /* 690 */ 310, 256, 243, 312, 254, 60, 256, 316, 254, 206, + /* 700 */ 256, 60, 218, 219, 43, 44, 45, 272, 47, 48, + /* 710 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 720 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 730 */ 113, 114, 240, 60, 241, 242, 118, 25, 102, 255, + /* 740 */ 166, 167, 101, 22, 26, 19, 20, 254, 22, 256, + /* 750 */ 139, 140, 117, 118, 119, 306, 195, 308, 117, 118, + /* 760 */ 237, 238, 36, 122, 103, 104, 105, 106, 107, 108, + /* 770 */ 109, 110, 111, 112, 113, 114, 195, 195, 60, 218, + /* 780 */ 219, 60, 109, 195, 19, 217, 60, 25, 23, 77, + /* 790 */ 117, 118, 119, 225, 233, 154, 155, 156, 72, 312, + /* 800 */ 218, 219, 90, 316, 22, 93, 303, 304, 43, 44, + /* 810 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54, + /* 820 */ 55, 56, 57, 58, 183, 195, 195, 101, 19, 213, + /* 830 */ 214, 243, 23, 107, 108, 117, 118, 119, 117, 118, + /* 840 */ 119, 115, 60, 117, 118, 119, 195, 60, 122, 218, + /* 850 */ 219, 22, 43, 44, 45, 35, 47, 48, 49, 50, + /* 860 */ 51, 52, 53, 54, 55, 56, 57, 58, 103, 104, + /* 870 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 880 */ 154, 155, 156, 157, 158, 195, 255, 67, 195, 60, + /* 890 */ 101, 240, 311, 312, 306, 75, 308, 316, 29, 117, + /* 900 */ 118, 119, 33, 287, 117, 118, 119, 118, 146, 183, + /* 910 */ 195, 122, 103, 104, 105, 106, 107, 108, 109, 110, + /* 920 */ 111, 112, 113, 114, 215, 195, 77, 60, 25, 195, + /* 930 */ 122, 144, 19, 218, 219, 66, 23, 88, 246, 90, + /* 940 */ 132, 25, 93, 154, 155, 156, 117, 118, 119, 257, + /* 950 */ 195, 131, 218, 219, 195, 265, 43, 44, 45, 195, + /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 970 */ 57, 58, 183, 218, 219, 195, 19, 218, 219, 195, + /* 980 */ 23, 195, 218, 219, 117, 118, 119, 195, 233, 255, + /* 990 */ 195, 195, 233, 22, 23, 146, 25, 233, 218, 219, + /* 1000 */ 43, 44, 45, 294, 47, 48, 49, 50, 51, 52, + /* 1010 */ 53, 54, 55, 56, 57, 58, 103, 104, 105, 106, + /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 12, + /* 1030 */ 234, 195, 240, 74, 195, 255, 195, 60, 243, 262, + /* 1040 */ 263, 311, 312, 25, 27, 19, 316, 107, 108, 265, + /* 1050 */ 24, 265, 195, 150, 195, 139, 140, 218, 219, 42, + /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + /* 1070 */ 113, 114, 233, 102, 67, 218, 219, 218, 219, 243, + /* 1080 */ 19, 64, 22, 23, 23, 25, 195, 128, 129, 130, + /* 1090 */ 233, 74, 233, 86, 154, 118, 156, 130, 265, 208, + /* 1100 */ 19, 306, 95, 308, 43, 44, 45, 266, 47, 48, + /* 1110 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 1120 */ 153, 230, 96, 232, 43, 44, 45, 19, 47, 48, + /* 1130 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + /* 1140 */ 114, 22, 306, 24, 308, 127, 120, 121, 122, 123, + /* 1150 */ 124, 125, 126, 195, 147, 212, 213, 214, 132, 23, + /* 1160 */ 195, 25, 102, 100, 103, 104, 105, 106, 107, 108, + /* 1170 */ 109, 110, 111, 112, 113, 114, 218, 219, 19, 60, + /* 1180 */ 195, 12, 210, 211, 103, 104, 105, 106, 107, 108, + /* 1190 */ 109, 110, 111, 112, 113, 114, 27, 134, 195, 195, + /* 1200 */ 195, 210, 211, 218, 219, 195, 47, 195, 212, 213, + /* 1210 */ 214, 42, 16, 130, 19, 112, 113, 114, 23, 77, + /* 1220 */ 195, 218, 219, 218, 219, 117, 163, 164, 218, 219, + /* 1230 */ 218, 219, 90, 64, 19, 93, 153, 118, 43, 44, + /* 1240 */ 45, 160, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1250 */ 55, 56, 57, 58, 195, 119, 272, 276, 43, 44, + /* 1260 */ 45, 195, 47, 48, 49, 50, 51, 52, 53, 54, + /* 1270 */ 55, 56, 57, 58, 78, 116, 80, 218, 219, 116, + /* 1280 */ 144, 128, 129, 130, 218, 219, 61, 195, 47, 195, + /* 1290 */ 16, 132, 195, 263, 195, 314, 315, 267, 103, 104, + /* 1300 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 1310 */ 218, 219, 218, 219, 151, 218, 219, 195, 103, 104, + /* 1320 */ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + /* 1330 */ 210, 211, 195, 7, 8, 9, 195, 60, 195, 312, + /* 1340 */ 218, 219, 195, 316, 195, 120, 195, 263, 19, 195, + /* 1350 */ 125, 267, 78, 24, 80, 218, 219, 116, 162, 218, + /* 1360 */ 219, 218, 219, 301, 302, 218, 219, 195, 19, 218, + /* 1370 */ 219, 276, 43, 44, 45, 160, 47, 48, 49, 50, + /* 1380 */ 51, 52, 53, 54, 55, 56, 57, 58, 19, 146, + /* 1390 */ 218, 219, 43, 44, 45, 118, 47, 48, 49, 50, + /* 1400 */ 51, 52, 53, 54, 55, 56, 57, 58, 165, 314, + /* 1410 */ 315, 276, 43, 44, 45, 266, 47, 48, 49, 50, + /* 1420 */ 51, 52, 53, 54, 55, 56, 57, 58, 128, 129, + /* 1430 */ 130, 195, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1440 */ 111, 112, 113, 114, 195, 228, 195, 61, 195, 314, + /* 1450 */ 315, 25, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1460 */ 111, 112, 113, 114, 195, 22, 195, 218, 219, 218, + /* 1470 */ 219, 195, 103, 104, 105, 106, 107, 108, 109, 110, + /* 1480 */ 111, 112, 113, 114, 195, 195, 246, 218, 219, 218, + /* 1490 */ 219, 25, 19, 246, 218, 219, 246, 257, 259, 260, + /* 1500 */ 195, 22, 266, 60, 257, 195, 120, 257, 218, 219, + /* 1510 */ 116, 195, 19, 195, 150, 151, 25, 44, 45, 266, + /* 1520 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1530 */ 57, 58, 195, 54, 218, 219, 218, 219, 45, 145, + /* 1540 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + /* 1550 */ 57, 58, 246, 121, 122, 218, 219, 19, 23, 31, + /* 1560 */ 25, 118, 159, 257, 161, 24, 195, 39, 195, 143, + /* 1570 */ 195, 19, 20, 22, 22, 24, 103, 104, 105, 106, + /* 1580 */ 107, 108, 109, 110, 111, 112, 113, 114, 36, 218, + /* 1590 */ 219, 218, 219, 218, 219, 195, 103, 104, 105, 106, + /* 1600 */ 107, 108, 109, 110, 111, 112, 113, 114, 195, 143, + /* 1610 */ 119, 136, 60, 195, 22, 195, 141, 195, 218, 219, + /* 1620 */ 195, 23, 195, 25, 72, 23, 131, 25, 195, 134, + /* 1630 */ 23, 218, 219, 195, 82, 144, 218, 219, 218, 219, + /* 1640 */ 218, 219, 195, 218, 219, 218, 219, 60, 23, 195, + /* 1650 */ 25, 218, 219, 101, 195, 117, 218, 219, 195, 107, + /* 1660 */ 108, 23, 195, 25, 195, 218, 219, 115, 228, 117, + /* 1670 */ 118, 119, 218, 219, 122, 195, 19, 218, 219, 195, + /* 1680 */ 60, 218, 219, 142, 195, 218, 219, 19, 20, 195, + /* 1690 */ 22, 139, 140, 23, 23, 25, 25, 195, 218, 219, + /* 1700 */ 7, 8, 218, 219, 36, 118, 154, 155, 156, 157, + /* 1710 */ 158, 195, 23, 195, 25, 84, 85, 49, 195, 23, + /* 1720 */ 195, 25, 195, 23, 195, 25, 195, 23, 60, 25, + /* 1730 */ 23, 23, 25, 25, 142, 183, 218, 219, 118, 195, + /* 1740 */ 72, 218, 219, 218, 219, 218, 219, 218, 219, 218, + /* 1750 */ 219, 195, 195, 146, 86, 98, 23, 195, 25, 91, + /* 1760 */ 19, 20, 154, 22, 156, 154, 23, 156, 25, 101, + /* 1770 */ 23, 195, 25, 195, 195, 107, 108, 36, 195, 195, + /* 1780 */ 195, 195, 228, 115, 195, 117, 118, 119, 195, 195, + /* 1790 */ 122, 261, 195, 321, 195, 195, 195, 258, 238, 195, + /* 1800 */ 195, 60, 299, 291, 195, 195, 258, 195, 195, 195, + /* 1810 */ 290, 244, 216, 72, 245, 193, 258, 258, 299, 258, + /* 1820 */ 299, 274, 154, 155, 156, 157, 158, 86, 247, 295, + /* 1830 */ 248, 295, 91, 19, 20, 270, 22, 274, 270, 248, + /* 1840 */ 274, 222, 101, 227, 274, 221, 231, 221, 107, 108, + /* 1850 */ 36, 183, 262, 247, 221, 283, 115, 262, 117, 118, + /* 1860 */ 119, 198, 116, 122, 220, 262, 61, 220, 220, 251, + /* 1870 */ 247, 142, 251, 245, 60, 202, 299, 202, 38, 262, + /* 1880 */ 202, 22, 152, 151, 296, 43, 72, 236, 18, 239, + /* 1890 */ 202, 239, 239, 239, 18, 154, 155, 156, 157, 158, + /* 1900 */ 86, 150, 201, 248, 275, 91, 248, 273, 236, 248, + /* 1910 */ 275, 275, 273, 236, 248, 101, 286, 202, 201, 159, + /* 1920 */ 63, 107, 108, 296, 183, 293, 202, 201, 22, 115, + /* 1930 */ 202, 117, 118, 119, 292, 223, 122, 201, 65, 202, + /* 1940 */ 201, 223, 220, 220, 22, 220, 226, 226, 229, 127, + /* 1950 */ 223, 220, 166, 24, 285, 220, 222, 114, 315, 285, + /* 1960 */ 220, 202, 220, 307, 92, 320, 320, 229, 154, 155, + /* 1970 */ 156, 157, 158, 0, 1, 2, 223, 83, 5, 268, + /* 1980 */ 149, 268, 146, 10, 11, 12, 13, 14, 22, 280, + /* 1990 */ 17, 202, 159, 19, 20, 251, 22, 183, 282, 148, + /* 2000 */ 252, 252, 250, 30, 249, 32, 248, 147, 25, 13, + /* 2010 */ 36, 204, 196, 40, 196, 6, 302, 194, 194, 194, + /* 2020 */ 209, 215, 209, 215, 215, 215, 224, 224, 216, 209, + /* 2030 */ 4, 216, 215, 3, 60, 22, 122, 19, 122, 19, + /* 2040 */ 125, 22, 15, 22, 71, 16, 72, 23, 23, 140, + /* 2050 */ 305, 152, 79, 25, 131, 82, 143, 20, 16, 305, + /* 2060 */ 1, 143, 145, 131, 131, 62, 54, 131, 37, 54, + /* 2070 */ 54, 152, 99, 117, 34, 101, 54, 24, 1, 5, + /* 2080 */ 22, 107, 108, 116, 76, 25, 162, 41, 142, 115, + /* 2090 */ 24, 117, 118, 119, 116, 20, 122, 19, 126, 23, + /* 2100 */ 132, 19, 20, 69, 22, 69, 22, 134, 22, 68, + /* 2110 */ 22, 22, 139, 140, 60, 141, 68, 24, 36, 28, + /* 2120 */ 97, 22, 37, 68, 23, 150, 34, 22, 154, 155, + /* 2130 */ 156, 157, 158, 23, 23, 22, 163, 25, 23, 142, + /* 2140 */ 23, 98, 60, 23, 22, 144, 25, 76, 34, 117, + /* 2150 */ 34, 89, 34, 34, 72, 87, 76, 183, 34, 94, + /* 2160 */ 34, 23, 22, 24, 34, 23, 25, 44, 25, 23, + /* 2170 */ 23, 23, 22, 22, 25, 11, 143, 25, 143, 23, + /* 2180 */ 22, 22, 22, 101, 23, 23, 136, 22, 25, 107, + /* 2190 */ 108, 142, 25, 142, 142, 23, 15, 115, 1, 117, + /* 2200 */ 118, 119, 1, 2, 122, 1, 5, 322, 322, 322, + /* 2210 */ 322, 10, 11, 12, 13, 14, 322, 322, 17, 322, + /* 2220 */ 5, 322, 322, 141, 322, 10, 11, 12, 13, 14, + /* 2230 */ 322, 30, 17, 32, 322, 322, 154, 155, 156, 157, + /* 2240 */ 158, 40, 322, 322, 322, 30, 322, 32, 322, 322, + /* 2250 */ 322, 322, 322, 322, 322, 40, 322, 322, 322, 322, + /* 2260 */ 322, 322, 322, 322, 322, 183, 322, 322, 322, 322, + /* 2270 */ 322, 322, 71, 322, 322, 322, 322, 322, 322, 322, + /* 2280 */ 79, 322, 322, 82, 322, 322, 71, 322, 322, 322, + /* 2290 */ 322, 322, 322, 322, 79, 322, 322, 82, 322, 322, + /* 2300 */ 99, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2310 */ 322, 322, 322, 322, 99, 322, 322, 322, 322, 322, + /* 2320 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2330 */ 322, 322, 322, 322, 322, 134, 322, 322, 322, 322, + /* 2340 */ 139, 140, 322, 322, 322, 322, 322, 322, 322, 134, + /* 2350 */ 322, 322, 322, 322, 139, 140, 322, 322, 322, 322, + /* 2360 */ 322, 322, 322, 322, 163, 322, 322, 322, 322, 322, + /* 2370 */ 322, 322, 322, 322, 322, 322, 322, 322, 163, 322, + /* 2380 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2390 */ 322, 322, 322, 322, 322, 322, 322, 322, 322, 322, + /* 2400 */ 322, 322, 322, 322, 322, 322, 322, 322, 187, 187, + /* 2410 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2420 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2430 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2440 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2450 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2460 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2470 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2480 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2490 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2500 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2510 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2520 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2530 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2540 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2550 */ 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, + /* 2560 */ 187, 187, 187, 187, 187, 187, }; -#define YY_SHIFT_COUNT (582) +#define YY_SHIFT_COUNT (599) #define YY_SHIFT_MIN (0) -#define YY_SHIFT_MAX (2152) +#define YY_SHIFT_MAX (2215) static const unsigned short int yy_shift_ofst[] = { - /* 0 */ 2029, 1801, 2043, 1380, 1380, 318, 271, 1496, 1569, 1642, - /* 10 */ 702, 702, 702, 740, 318, 318, 318, 318, 318, 0, - /* 20 */ 0, 216, 1177, 702, 702, 702, 702, 702, 702, 702, - /* 30 */ 702, 702, 702, 702, 702, 702, 702, 702, 503, 503, - /* 40 */ 111, 111, 217, 287, 348, 610, 610, 736, 736, 736, - /* 50 */ 736, 40, 112, 320, 340, 445, 489, 593, 637, 741, - /* 60 */ 785, 889, 909, 1023, 1043, 1157, 1177, 1177, 1177, 1177, - /* 70 */ 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - /* 80 */ 1177, 1177, 1177, 1177, 1197, 1177, 1301, 1321, 1321, 554, - /* 90 */ 1802, 1910, 702, 702, 702, 702, 702, 702, 702, 702, - /* 100 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 110 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 120 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 130 */ 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - /* 140 */ 702, 702, 138, 198, 198, 198, 198, 198, 198, 198, - /* 150 */ 183, 99, 169, 549, 610, 151, 542, 610, 610, 1017, - /* 160 */ 1017, 610, 1001, 350, 464, 464, 464, 586, 1, 1, - /* 170 */ 2207, 2207, 854, 854, 854, 465, 694, 694, 694, 694, - /* 180 */ 1096, 1096, 825, 549, 847, 904, 610, 610, 610, 610, - /* 190 */ 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, - /* 200 */ 610, 610, 610, 610, 610, 488, 947, 947, 610, 1129, - /* 210 */ 495, 495, 1139, 1139, 967, 967, 1173, 2207, 2207, 2207, - /* 220 */ 2207, 2207, 2207, 2207, 617, 765, 765, 697, 444, 708, - /* 230 */ 660, 745, 510, 663, 864, 610, 610, 610, 610, 610, - /* 240 */ 610, 610, 610, 610, 610, 188, 610, 610, 610, 610, - /* 250 */ 610, 610, 610, 610, 610, 610, 610, 610, 839, 839, - /* 260 */ 839, 610, 610, 610, 1155, 610, 610, 610, 1119, 1247, - /* 270 */ 610, 1353, 610, 610, 610, 610, 610, 610, 610, 610, - /* 280 */ 1063, 494, 1101, 291, 291, 291, 291, 1319, 1101, 1101, - /* 290 */ 775, 1221, 1375, 1452, 667, 1341, 1198, 1341, 1435, 1487, - /* 300 */ 667, 667, 1487, 667, 1198, 1435, 777, 1011, 1423, 584, - /* 310 */ 584, 584, 1273, 1273, 1273, 1273, 1471, 1471, 880, 1530, - /* 320 */ 1190, 1095, 1731, 1731, 1668, 1668, 1794, 1794, 1668, 1683, - /* 330 */ 1685, 1815, 1796, 1824, 1824, 1824, 1824, 1668, 1828, 1701, - /* 340 */ 1685, 1685, 1701, 1815, 1796, 1701, 1796, 1701, 1668, 1828, - /* 350 */ 1697, 1800, 1668, 1828, 1848, 1668, 1828, 1668, 1828, 1848, - /* 360 */ 1766, 1766, 1766, 1823, 1870, 1870, 1848, 1766, 1767, 1766, - /* 370 */ 1823, 1766, 1766, 1727, 1872, 1783, 1783, 1848, 1668, 1813, - /* 380 */ 1813, 1825, 1825, 1777, 1781, 1906, 1668, 1774, 1777, 1789, - /* 390 */ 1792, 1701, 1919, 1935, 1935, 1949, 1949, 1949, 2207, 2207, - /* 400 */ 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, - /* 410 */ 2207, 2207, 2207, 69, 1032, 79, 357, 1377, 1206, 400, - /* 420 */ 1525, 835, 332, 1540, 1437, 1539, 1536, 1548, 1583, 1620, - /* 430 */ 1633, 1670, 1671, 1674, 1567, 1553, 1682, 1506, 1675, 1358, - /* 440 */ 1607, 1589, 1678, 1681, 1624, 1687, 1688, 1283, 1561, 1693, - /* 450 */ 1696, 1623, 1521, 1976, 1980, 1962, 1822, 1972, 1973, 1965, - /* 460 */ 1967, 1851, 1840, 1862, 1969, 1969, 1971, 1853, 1977, 1854, - /* 470 */ 1982, 1999, 1858, 1871, 1969, 1873, 1941, 1968, 1969, 1855, - /* 480 */ 1952, 1954, 1955, 1956, 1881, 1896, 1981, 1874, 2013, 2014, - /* 490 */ 1998, 1905, 1860, 1957, 2008, 1966, 1947, 1983, 1894, 1921, - /* 500 */ 2020, 2018, 2026, 1915, 1923, 2028, 1984, 2036, 2040, 2047, - /* 510 */ 2041, 2003, 2012, 2050, 1979, 2049, 2056, 2011, 2044, 2057, - /* 520 */ 2048, 1934, 2063, 2064, 2065, 2061, 2066, 2068, 1993, 1950, - /* 530 */ 2071, 2072, 1985, 2062, 2075, 1959, 2073, 2067, 2070, 2076, - /* 540 */ 2078, 2010, 2030, 2022, 2069, 2031, 2021, 2082, 2094, 2083, - /* 550 */ 2095, 2093, 2096, 2086, 1986, 1987, 2100, 2073, 2101, 2103, - /* 560 */ 2104, 2109, 2107, 2108, 2111, 2113, 2125, 2115, 2116, 2117, - /* 570 */ 2118, 2121, 2122, 2114, 2009, 2004, 2005, 2006, 2124, 2127, - /* 580 */ 2136, 2151, 2152, + /* 0 */ 2201, 1973, 2215, 1552, 1552, 33, 368, 1668, 1741, 1814, + /* 10 */ 726, 726, 726, 265, 33, 33, 33, 33, 33, 0, + /* 20 */ 0, 216, 1349, 726, 726, 726, 726, 726, 726, 726, + /* 30 */ 726, 726, 726, 726, 726, 726, 726, 726, 272, 272, + /* 40 */ 111, 111, 316, 365, 516, 867, 867, 916, 916, 916, + /* 50 */ 916, 40, 112, 260, 364, 408, 512, 617, 661, 765, + /* 60 */ 809, 913, 957, 1061, 1081, 1195, 1215, 1329, 1349, 1349, + /* 70 */ 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, 1349, + /* 80 */ 1349, 1349, 1349, 1349, 1349, 1349, 1369, 1349, 1473, 1493, + /* 90 */ 1493, 473, 1974, 2082, 726, 726, 726, 726, 726, 726, + /* 100 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 110 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 120 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 130 */ 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, + /* 140 */ 726, 726, 726, 726, 726, 726, 138, 232, 232, 232, + /* 150 */ 232, 232, 232, 232, 188, 99, 242, 718, 416, 1159, + /* 160 */ 867, 867, 940, 940, 867, 1103, 417, 574, 574, 574, + /* 170 */ 611, 139, 139, 2379, 2379, 1026, 1026, 1026, 536, 466, + /* 180 */ 466, 466, 466, 1017, 1017, 849, 718, 971, 1060, 867, + /* 190 */ 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 200 */ 867, 867, 867, 867, 867, 867, 867, 867, 261, 712, + /* 210 */ 712, 867, 108, 1142, 1142, 977, 1108, 1108, 977, 977, + /* 220 */ 1243, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 641, 789, + /* 230 */ 789, 635, 366, 721, 673, 782, 494, 787, 829, 867, + /* 240 */ 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 250 */ 959, 867, 867, 867, 867, 867, 867, 867, 867, 867, + /* 260 */ 867, 867, 867, 867, 867, 820, 820, 820, 867, 867, + /* 270 */ 867, 1136, 867, 867, 867, 1119, 1007, 867, 1169, 867, + /* 280 */ 867, 867, 867, 867, 867, 867, 867, 1225, 1153, 869, + /* 290 */ 196, 618, 618, 618, 618, 1491, 196, 196, 91, 339, + /* 300 */ 1326, 1386, 383, 1163, 1364, 1426, 1364, 1538, 903, 1163, + /* 310 */ 1163, 903, 1163, 1426, 1538, 1018, 1535, 1241, 1528, 1528, + /* 320 */ 1528, 1394, 1394, 1394, 1394, 762, 762, 1403, 1466, 1475, + /* 330 */ 1551, 1746, 1805, 1746, 1746, 1729, 1729, 1840, 1840, 1729, + /* 340 */ 1730, 1732, 1859, 1842, 1870, 1870, 1870, 1870, 1729, 1876, + /* 350 */ 1751, 1732, 1732, 1751, 1859, 1842, 1751, 1842, 1751, 1729, + /* 360 */ 1876, 1760, 1857, 1729, 1876, 1906, 1729, 1876, 1729, 1876, + /* 370 */ 1906, 1746, 1746, 1746, 1873, 1922, 1922, 1906, 1746, 1822, + /* 380 */ 1746, 1873, 1746, 1746, 1786, 1929, 1843, 1843, 1906, 1729, + /* 390 */ 1872, 1872, 1894, 1894, 1831, 1836, 1966, 1729, 1833, 1831, + /* 400 */ 1851, 1860, 1751, 1983, 1996, 1996, 2009, 2009, 2009, 2379, + /* 410 */ 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, 2379, + /* 420 */ 2379, 2379, 2379, 2379, 136, 1063, 1196, 530, 636, 1274, + /* 430 */ 1300, 1443, 1598, 1495, 1479, 967, 1083, 1602, 463, 1625, + /* 440 */ 1638, 1670, 1541, 1671, 1689, 1696, 1277, 1432, 1693, 808, + /* 450 */ 1700, 1607, 1657, 1587, 1704, 1707, 1631, 1708, 1733, 1608, + /* 460 */ 1611, 1743, 1747, 1620, 1592, 2026, 2030, 2013, 1914, 2018, + /* 470 */ 1916, 2020, 2019, 2021, 1915, 2027, 2029, 2024, 2025, 1909, + /* 480 */ 1899, 1923, 2028, 2028, 1913, 2037, 1917, 2042, 2059, 1918, + /* 490 */ 1932, 2028, 1933, 2003, 2031, 2028, 1919, 2012, 2015, 2016, + /* 500 */ 2022, 1936, 1956, 2040, 2053, 2077, 2074, 2058, 1967, 1924, + /* 510 */ 2034, 2060, 2036, 2008, 2046, 1946, 1978, 2066, 2075, 2078, + /* 520 */ 1968, 1972, 2084, 2041, 2086, 2088, 2076, 2089, 2048, 2054, + /* 530 */ 2093, 2023, 2091, 2099, 2055, 2085, 2101, 2092, 1975, 2105, + /* 540 */ 2110, 2111, 2112, 2115, 2113, 2043, 1997, 2117, 2120, 2032, + /* 550 */ 2114, 2122, 2001, 2121, 2116, 2118, 2119, 2124, 2062, 2071, + /* 560 */ 2068, 2123, 2080, 2065, 2126, 2138, 2140, 2139, 2141, 2143, + /* 570 */ 2130, 2033, 2035, 2142, 2121, 2146, 2147, 2148, 2150, 2149, + /* 580 */ 2152, 2156, 2151, 2164, 2158, 2159, 2161, 2162, 2160, 2165, + /* 590 */ 2163, 2050, 2049, 2051, 2052, 2167, 2172, 2181, 2197, 2204, }; -#define YY_REDUCE_COUNT (412) -#define YY_REDUCE_MIN (-277) -#define YY_REDUCE_MAX (1772) +#define YY_REDUCE_COUNT (423) +#define YY_REDUCE_MIN (-303) +#define YY_REDUCE_MAX (1825) static const short yy_reduce_ofst[] = { - /* 0 */ -67, 1252, -64, -178, -181, 160, 1071, 143, -184, 137, - /* 10 */ 218, 220, 222, -174, 229, 268, 272, 275, 324, -208, - /* 20 */ 242, -277, -39, 81, 537, 792, 810, 812, -189, 814, - /* 30 */ 831, 163, 865, 944, 887, 840, 964, 1077, -187, 292, - /* 40 */ -133, 274, 673, 558, 682, 795, 809, -238, -232, -238, - /* 50 */ -232, 329, 329, 329, 329, 329, 329, 329, 329, 329, - /* 60 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, - /* 70 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 329, - /* 80 */ 329, 329, 329, 329, 329, 329, 329, 329, 329, 557, - /* 90 */ 712, 949, 966, 969, 971, 979, 1097, 1099, 1103, 1142, - /* 100 */ 1144, 1169, 1172, 1201, 1203, 1228, 1241, 1250, 1253, 1255, - /* 110 */ 1261, 1266, 1271, 1282, 1291, 1308, 1310, 1312, 1322, 1328, - /* 120 */ 1347, 1354, 1356, 1359, 1362, 1365, 1367, 1374, 1376, 1381, - /* 130 */ 1401, 1403, 1406, 1412, 1414, 1417, 1421, 1428, 1447, 1449, - /* 140 */ 1453, 1462, 329, 329, 329, 329, 329, 329, 329, 329, - /* 150 */ 329, 329, 329, -22, -159, 475, -220, 756, 38, 501, - /* 160 */ 841, 714, 329, 118, 337, 349, 363, -56, 329, 329, - /* 170 */ 329, 329, -205, -205, -205, 687, -172, -130, -57, 790, - /* 180 */ 397, 528, -271, 136, 596, 596, 90, 316, 522, 541, - /* 190 */ -37, 715, 849, 977, 628, 856, 980, 991, 1081, 1102, - /* 200 */ 1135, 1083, -162, 208, 1258, 794, -86, 159, 41, 1109, - /* 210 */ 671, 852, 844, 932, 1175, 1254, 480, 1180, 100, 258, - /* 220 */ 1265, 1268, 1216, 1287, -139, 317, 344, 63, 339, 423, - /* 230 */ 563, 636, 676, 813, 908, 914, 950, 1078, 1084, 1098, - /* 240 */ 1363, 1384, 1407, 1439, 1464, 411, 1527, 1534, 1535, 1537, - /* 250 */ 1541, 1542, 1543, 1544, 1545, 1547, 1549, 1550, 990, 1164, - /* 260 */ 1492, 1551, 1552, 1556, 1217, 1558, 1559, 1560, 1473, 1413, - /* 270 */ 1563, 1510, 1568, 563, 1570, 1571, 1572, 1573, 1574, 1575, - /* 280 */ 1443, 1466, 1518, 1513, 1514, 1515, 1516, 1217, 1518, 1518, - /* 290 */ 1531, 1562, 1582, 1477, 1505, 1511, 1533, 1512, 1488, 1538, - /* 300 */ 1509, 1517, 1546, 1519, 1557, 1489, 1565, 1564, 1578, 1586, - /* 310 */ 1587, 1588, 1526, 1528, 1554, 1555, 1576, 1577, 1566, 1579, - /* 320 */ 1584, 1591, 1520, 1523, 1617, 1628, 1580, 1581, 1632, 1585, - /* 330 */ 1590, 1593, 1604, 1605, 1606, 1608, 1609, 1641, 1649, 1610, - /* 340 */ 1592, 1594, 1611, 1595, 1616, 1612, 1618, 1613, 1651, 1654, - /* 350 */ 1596, 1598, 1655, 1663, 1650, 1673, 1680, 1677, 1684, 1653, - /* 360 */ 1664, 1666, 1667, 1662, 1669, 1672, 1676, 1686, 1679, 1691, - /* 370 */ 1689, 1692, 1694, 1597, 1599, 1619, 1630, 1699, 1700, 1602, - /* 380 */ 1615, 1648, 1657, 1690, 1698, 1658, 1729, 1652, 1695, 1702, - /* 390 */ 1704, 1703, 1741, 1754, 1758, 1768, 1769, 1771, 1660, 1661, - /* 400 */ 1665, 1752, 1756, 1757, 1759, 1760, 1764, 1745, 1753, 1762, - /* 410 */ 1763, 1761, 1772, + /* 0 */ -67, 345, -64, -178, -181, 143, 435, -78, -183, 163, + /* 10 */ -185, 284, 384, -174, 189, 352, 440, 444, 493, -23, + /* 20 */ 227, -277, -1, 305, 561, 755, 759, 764, -189, 839, + /* 30 */ 857, 354, 484, 859, 631, 67, 734, 780, -187, 616, + /* 40 */ 581, 730, 891, 449, 588, 795, 836, -238, 287, -238, + /* 50 */ 287, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 60 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 70 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 80 */ -256, -256, -256, -256, -256, -256, -256, -256, -256, -256, + /* 90 */ -256, 205, 582, 715, 958, 985, 1003, 1005, 1010, 1012, + /* 100 */ 1059, 1066, 1092, 1094, 1097, 1122, 1137, 1141, 1143, 1147, + /* 110 */ 1151, 1172, 1249, 1251, 1269, 1271, 1276, 1290, 1316, 1318, + /* 120 */ 1337, 1371, 1373, 1375, 1400, 1413, 1418, 1420, 1422, 1425, + /* 130 */ 1427, 1433, 1438, 1447, 1454, 1459, 1463, 1467, 1480, 1484, + /* 140 */ 1518, 1523, 1525, 1527, 1529, 1531, -256, -256, -256, -256, + /* 150 */ -256, -256, -256, -256, -256, -256, -256, 155, 210, -220, + /* 160 */ 86, -130, 943, 996, 402, -256, -113, 981, 1095, 1135, + /* 170 */ 395, -256, -256, -256, -256, 568, 568, 568, -4, -153, + /* 180 */ -133, 259, 306, -166, 523, -303, -126, 503, 503, -37, + /* 190 */ -149, 164, 690, 292, 412, 492, 651, 784, 332, 786, + /* 200 */ 841, 1149, 833, 1236, 792, 162, 796, 1253, 777, 288, + /* 210 */ 381, 380, 709, 487, 1027, 972, 1030, 1084, 991, 1120, + /* 220 */ -152, 1062, 692, 1240, 1247, 1250, 1239, 1306, -207, -194, + /* 230 */ 57, 180, 74, 315, 355, 376, 452, 488, 630, 693, + /* 240 */ 965, 1004, 1025, 1099, 1154, 1289, 1305, 1310, 1469, 1489, + /* 250 */ 984, 1494, 1502, 1516, 1544, 1556, 1557, 1562, 1576, 1578, + /* 260 */ 1579, 1583, 1584, 1585, 1586, 1217, 1440, 1554, 1589, 1593, + /* 270 */ 1594, 1530, 1597, 1599, 1600, 1539, 1472, 1601, 1560, 1604, + /* 280 */ 355, 1605, 1609, 1610, 1612, 1613, 1614, 1503, 1512, 1520, + /* 290 */ 1567, 1548, 1558, 1559, 1561, 1530, 1567, 1567, 1569, 1596, + /* 300 */ 1622, 1519, 1521, 1547, 1565, 1581, 1568, 1534, 1582, 1563, + /* 310 */ 1566, 1591, 1570, 1606, 1536, 1619, 1615, 1616, 1624, 1626, + /* 320 */ 1633, 1590, 1595, 1603, 1617, 1618, 1621, 1572, 1623, 1628, + /* 330 */ 1663, 1644, 1577, 1647, 1648, 1673, 1675, 1588, 1627, 1678, + /* 340 */ 1630, 1629, 1634, 1651, 1650, 1652, 1653, 1654, 1688, 1701, + /* 350 */ 1655, 1635, 1636, 1658, 1639, 1672, 1661, 1677, 1666, 1715, + /* 360 */ 1717, 1632, 1642, 1724, 1726, 1712, 1728, 1736, 1737, 1739, + /* 370 */ 1718, 1722, 1723, 1725, 1719, 1720, 1721, 1727, 1731, 1734, + /* 380 */ 1735, 1738, 1740, 1742, 1643, 1656, 1669, 1674, 1753, 1759, + /* 390 */ 1645, 1646, 1711, 1713, 1748, 1744, 1709, 1789, 1716, 1749, + /* 400 */ 1752, 1755, 1758, 1807, 1816, 1818, 1823, 1824, 1825, 1745, + /* 410 */ 1754, 1714, 1811, 1806, 1808, 1809, 1810, 1813, 1802, 1803, + /* 420 */ 1812, 1815, 1817, 1820, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 1663, 1663, 1663, 1491, 1254, 1367, 1254, 1254, 1254, 1254, - /* 10 */ 1491, 1491, 1491, 1254, 1254, 1254, 1254, 1254, 1254, 1397, - /* 20 */ 1397, 1544, 1287, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 30 */ 1254, 1254, 1254, 1254, 1254, 1490, 1254, 1254, 1254, 1254, - /* 40 */ 1578, 1578, 1254, 1254, 1254, 1254, 1254, 1563, 1562, 1254, - /* 50 */ 1254, 1254, 1406, 1254, 1413, 1254, 1254, 1254, 1254, 1254, - /* 60 */ 1492, 1493, 1254, 1254, 1254, 1254, 1543, 1545, 1508, 1420, - /* 70 */ 1419, 1418, 1417, 1526, 1385, 1411, 1404, 1408, 1487, 1488, - /* 80 */ 1486, 1641, 1493, 1492, 1254, 1407, 1455, 1471, 1454, 1254, - /* 90 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 100 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 110 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 120 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 130 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 140 */ 1254, 1254, 1463, 1470, 1469, 1468, 1477, 1467, 1464, 1457, - /* 150 */ 1456, 1458, 1459, 1278, 1254, 1275, 1329, 1254, 1254, 1254, - /* 160 */ 1254, 1254, 1460, 1287, 1448, 1447, 1446, 1254, 1474, 1461, - /* 170 */ 1473, 1472, 1551, 1615, 1614, 1509, 1254, 1254, 1254, 1254, - /* 180 */ 1254, 1254, 1578, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 190 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 200 */ 1254, 1254, 1254, 1254, 1254, 1387, 1578, 1578, 1254, 1287, - /* 210 */ 1578, 1578, 1388, 1388, 1283, 1283, 1391, 1558, 1358, 1358, - /* 220 */ 1358, 1358, 1367, 1358, 1254, 1254, 1254, 1254, 1254, 1254, - /* 230 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1548, - /* 240 */ 1546, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 250 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 260 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1363, 1254, - /* 270 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1608, - /* 280 */ 1254, 1521, 1343, 1363, 1363, 1363, 1363, 1365, 1344, 1342, - /* 290 */ 1357, 1288, 1261, 1655, 1423, 1412, 1364, 1412, 1652, 1410, - /* 300 */ 1423, 1423, 1410, 1423, 1364, 1652, 1304, 1630, 1299, 1397, - /* 310 */ 1397, 1397, 1387, 1387, 1387, 1387, 1391, 1391, 1489, 1364, - /* 320 */ 1357, 1254, 1655, 1655, 1373, 1373, 1654, 1654, 1373, 1509, - /* 330 */ 1638, 1432, 1332, 1338, 1338, 1338, 1338, 1373, 1272, 1410, - /* 340 */ 1638, 1638, 1410, 1432, 1332, 1410, 1332, 1410, 1373, 1272, - /* 350 */ 1525, 1649, 1373, 1272, 1499, 1373, 1272, 1373, 1272, 1499, - /* 360 */ 1330, 1330, 1330, 1319, 1254, 1254, 1499, 1330, 1304, 1330, - /* 370 */ 1319, 1330, 1330, 1596, 1254, 1503, 1503, 1499, 1373, 1588, - /* 380 */ 1588, 1400, 1400, 1405, 1391, 1494, 1373, 1254, 1405, 1403, - /* 390 */ 1401, 1410, 1322, 1611, 1611, 1607, 1607, 1607, 1660, 1660, - /* 400 */ 1558, 1623, 1287, 1287, 1287, 1287, 1623, 1306, 1306, 1288, - /* 410 */ 1288, 1287, 1623, 1254, 1254, 1254, 1254, 1254, 1254, 1618, - /* 420 */ 1254, 1553, 1510, 1377, 1254, 1254, 1254, 1254, 1254, 1254, - /* 430 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 440 */ 1564, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 450 */ 1254, 1254, 1437, 1254, 1257, 1555, 1254, 1254, 1254, 1254, - /* 460 */ 1254, 1254, 1254, 1254, 1414, 1415, 1378, 1254, 1254, 1254, - /* 470 */ 1254, 1254, 1254, 1254, 1429, 1254, 1254, 1254, 1424, 1254, - /* 480 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1651, 1254, 1254, - /* 490 */ 1254, 1254, 1254, 1254, 1524, 1523, 1254, 1254, 1375, 1254, - /* 500 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 510 */ 1254, 1254, 1302, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 520 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 530 */ 1254, 1254, 1254, 1254, 1254, 1254, 1402, 1254, 1254, 1254, - /* 540 */ 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 550 */ 1254, 1593, 1392, 1254, 1254, 1254, 1254, 1642, 1254, 1254, - /* 560 */ 1254, 1254, 1352, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - /* 570 */ 1254, 1254, 1254, 1634, 1346, 1438, 1254, 1441, 1276, 1254, - /* 580 */ 1266, 1254, 1254, + /* 0 */ 1691, 1691, 1691, 1516, 1279, 1392, 1279, 1279, 1279, 1279, + /* 10 */ 1516, 1516, 1516, 1279, 1279, 1279, 1279, 1279, 1279, 1422, + /* 20 */ 1422, 1568, 1312, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 30 */ 1279, 1279, 1279, 1279, 1279, 1515, 1279, 1279, 1279, 1279, + /* 40 */ 1607, 1607, 1279, 1279, 1279, 1279, 1279, 1592, 1591, 1279, + /* 50 */ 1279, 1279, 1431, 1279, 1279, 1279, 1438, 1279, 1279, 1279, + /* 60 */ 1279, 1279, 1517, 1518, 1279, 1279, 1279, 1279, 1567, 1569, + /* 70 */ 1533, 1445, 1444, 1443, 1442, 1551, 1410, 1436, 1429, 1433, + /* 80 */ 1512, 1513, 1511, 1670, 1518, 1517, 1279, 1432, 1480, 1496, + /* 90 */ 1479, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 100 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 110 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 120 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 130 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 140 */ 1279, 1279, 1279, 1279, 1279, 1279, 1488, 1495, 1494, 1493, + /* 150 */ 1502, 1492, 1489, 1482, 1481, 1483, 1484, 1303, 1300, 1354, + /* 160 */ 1279, 1279, 1279, 1279, 1279, 1485, 1312, 1473, 1472, 1471, + /* 170 */ 1279, 1499, 1486, 1498, 1497, 1575, 1644, 1643, 1534, 1279, + /* 180 */ 1279, 1279, 1279, 1279, 1279, 1607, 1279, 1279, 1279, 1279, + /* 190 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 200 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1412, 1607, + /* 210 */ 1607, 1279, 1312, 1607, 1607, 1308, 1413, 1413, 1308, 1308, + /* 220 */ 1416, 1587, 1383, 1383, 1383, 1383, 1392, 1383, 1279, 1279, + /* 230 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 240 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1572, 1570, 1279, + /* 250 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 260 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 270 */ 1279, 1279, 1279, 1279, 1279, 1388, 1279, 1279, 1279, 1279, + /* 280 */ 1279, 1279, 1279, 1279, 1279, 1279, 1637, 1683, 1279, 1546, + /* 290 */ 1368, 1388, 1388, 1388, 1388, 1390, 1369, 1367, 1382, 1313, + /* 300 */ 1286, 1683, 1683, 1448, 1437, 1389, 1437, 1680, 1435, 1448, + /* 310 */ 1448, 1435, 1448, 1389, 1680, 1329, 1659, 1324, 1422, 1422, + /* 320 */ 1422, 1412, 1412, 1412, 1412, 1416, 1416, 1514, 1389, 1382, + /* 330 */ 1279, 1355, 1683, 1355, 1355, 1398, 1398, 1682, 1682, 1398, + /* 340 */ 1534, 1667, 1457, 1357, 1363, 1363, 1363, 1363, 1398, 1297, + /* 350 */ 1435, 1667, 1667, 1435, 1457, 1357, 1435, 1357, 1435, 1398, + /* 360 */ 1297, 1550, 1678, 1398, 1297, 1524, 1398, 1297, 1398, 1297, + /* 370 */ 1524, 1355, 1355, 1355, 1344, 1279, 1279, 1524, 1355, 1329, + /* 380 */ 1355, 1344, 1355, 1355, 1625, 1279, 1528, 1528, 1524, 1398, + /* 390 */ 1617, 1617, 1425, 1425, 1430, 1416, 1519, 1398, 1279, 1430, + /* 400 */ 1428, 1426, 1435, 1347, 1640, 1640, 1636, 1636, 1636, 1688, + /* 410 */ 1688, 1587, 1652, 1312, 1312, 1312, 1312, 1652, 1331, 1331, + /* 420 */ 1313, 1313, 1312, 1652, 1279, 1279, 1279, 1279, 1279, 1279, + /* 430 */ 1279, 1647, 1279, 1279, 1535, 1279, 1279, 1279, 1279, 1279, + /* 440 */ 1279, 1279, 1402, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 450 */ 1279, 1279, 1593, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 460 */ 1279, 1279, 1279, 1279, 1462, 1279, 1282, 1584, 1279, 1279, + /* 470 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 480 */ 1279, 1279, 1439, 1440, 1279, 1279, 1279, 1279, 1279, 1279, + /* 490 */ 1279, 1454, 1279, 1279, 1279, 1449, 1279, 1279, 1279, 1279, + /* 500 */ 1279, 1279, 1279, 1279, 1403, 1279, 1279, 1279, 1279, 1279, + /* 510 */ 1279, 1549, 1548, 1279, 1279, 1400, 1279, 1279, 1279, 1279, + /* 520 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1327, + /* 530 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 540 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 550 */ 1279, 1279, 1279, 1427, 1279, 1279, 1279, 1279, 1279, 1279, + /* 560 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1622, 1417, + /* 570 */ 1279, 1279, 1279, 1279, 1671, 1279, 1279, 1279, 1279, 1377, + /* 580 */ 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, 1279, + /* 590 */ 1663, 1371, 1463, 1279, 1466, 1301, 1279, 1291, 1279, 1279, }; /********** End of lemon-generated parsing tables *****************************/ @@ -179376,34 +181516,33 @@ static const char *const yyTokenName[] = { /* 292 */ "foreach_clause", /* 293 */ "when_clause", /* 294 */ "trigger_cmd", - /* 295 */ "trnm", - /* 296 */ "tridxby", - /* 297 */ "database_kw_opt", - /* 298 */ "key_opt", - /* 299 */ "add_column_fullname", - /* 300 */ "kwcolumn_opt", - /* 301 */ "create_vtab", - /* 302 */ "vtabarglist", - /* 303 */ "vtabarg", - /* 304 */ "vtabargtoken", - /* 305 */ "lp", - /* 306 */ "anylist", - /* 307 */ "wqitem", - /* 308 */ "wqas", - /* 309 */ "withnm", - /* 310 */ "windowdefn_list", - /* 311 */ "windowdefn", - /* 312 */ "window", - /* 313 */ "frame_opt", - /* 314 */ "part_opt", - /* 315 */ "filter_clause", - /* 316 */ "over_clause", - /* 317 */ "range_or_rows", - /* 318 */ "frame_bound", - /* 319 */ "frame_bound_s", - /* 320 */ "frame_bound_e", - /* 321 */ "frame_exclude_opt", - /* 322 */ "frame_exclude", + /* 295 */ "tridxby", + /* 296 */ "database_kw_opt", + /* 297 */ "key_opt", + /* 298 */ "alter_add", + /* 299 */ "kwcolumn_opt", + /* 300 */ "create_vtab", + /* 301 */ "vtabarglist", + /* 302 */ "vtabarg", + /* 303 */ "vtabargtoken", + /* 304 */ "lp", + /* 305 */ "anylist", + /* 306 */ "wqitem", + /* 307 */ "wqas", + /* 308 */ "withnm", + /* 309 */ "windowdefn_list", + /* 310 */ "windowdefn", + /* 311 */ "window", + /* 312 */ "frame_opt", + /* 313 */ "part_opt", + /* 314 */ "filter_clause", + /* 315 */ "over_clause", + /* 316 */ "range_or_rows", + /* 317 */ "frame_bound", + /* 318 */ "frame_bound_s", + /* 319 */ "frame_bound_e", + /* 320 */ "frame_exclude_opt", + /* 321 */ "frame_exclude", }; #endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ @@ -179533,8 +181672,8 @@ static const char *const yyRuleName[] = { /* 119 */ "fullname ::= nm DOT nm", /* 120 */ "xfullname ::= nm", /* 121 */ "xfullname ::= nm DOT nm", - /* 122 */ "xfullname ::= nm DOT nm AS nm", - /* 123 */ "xfullname ::= nm AS nm", + /* 122 */ "xfullname ::= nm AS nm", + /* 123 */ "xfullname ::= nm DOT nm AS nm", /* 124 */ "joinop ::= COMMA|JOIN", /* 125 */ "joinop ::= JOIN_KW JOIN", /* 126 */ "joinop ::= JOIN_KW nm JOIN", @@ -179683,143 +181822,146 @@ static const char *const yyRuleName[] = { /* 269 */ "when_clause ::= WHEN expr", /* 270 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI", /* 271 */ "trigger_cmd_list ::= trigger_cmd SEMI", - /* 272 */ "trnm ::= nm DOT nm", - /* 273 */ "tridxby ::= INDEXED BY nm", - /* 274 */ "tridxby ::= NOT INDEXED", - /* 275 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt", - /* 276 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt", - /* 277 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt", - /* 278 */ "trigger_cmd ::= scanpt select scanpt", - /* 279 */ "expr ::= RAISE LP IGNORE RP", - /* 280 */ "expr ::= RAISE LP raisetype COMMA expr RP", - /* 281 */ "raisetype ::= ROLLBACK", - /* 282 */ "raisetype ::= ABORT", - /* 283 */ "raisetype ::= FAIL", - /* 284 */ "cmd ::= DROP TRIGGER ifexists fullname", - /* 285 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", - /* 286 */ "cmd ::= DETACH database_kw_opt expr", - /* 287 */ "key_opt ::=", - /* 288 */ "key_opt ::= KEY expr", - /* 289 */ "cmd ::= REINDEX", - /* 290 */ "cmd ::= REINDEX nm dbnm", - /* 291 */ "cmd ::= ANALYZE", - /* 292 */ "cmd ::= ANALYZE nm dbnm", - /* 293 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 294 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist", + /* 272 */ "tridxby ::= INDEXED BY nm", + /* 273 */ "tridxby ::= NOT INDEXED", + /* 274 */ "trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt", + /* 275 */ "trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt", + /* 276 */ "trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt", + /* 277 */ "trigger_cmd ::= scanpt select scanpt", + /* 278 */ "expr ::= RAISE LP IGNORE RP", + /* 279 */ "expr ::= RAISE LP raisetype COMMA expr RP", + /* 280 */ "raisetype ::= ROLLBACK", + /* 281 */ "raisetype ::= ABORT", + /* 282 */ "raisetype ::= FAIL", + /* 283 */ "cmd ::= DROP TRIGGER ifexists fullname", + /* 284 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 285 */ "cmd ::= DETACH database_kw_opt expr", + /* 286 */ "key_opt ::=", + /* 287 */ "key_opt ::= KEY expr", + /* 288 */ "cmd ::= REINDEX", + /* 289 */ "cmd ::= REINDEX nm dbnm", + /* 290 */ "cmd ::= ANALYZE", + /* 291 */ "cmd ::= ANALYZE nm dbnm", + /* 292 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 293 */ "cmd ::= alter_add carglist", + /* 294 */ "alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken", /* 295 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm", - /* 296 */ "add_column_fullname ::= fullname", - /* 297 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", - /* 298 */ "cmd ::= create_vtab", - /* 299 */ "cmd ::= create_vtab LP vtabarglist RP", - /* 300 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", - /* 301 */ "vtabarg ::=", - /* 302 */ "vtabargtoken ::= ANY", - /* 303 */ "vtabargtoken ::= lp anylist RP", - /* 304 */ "lp ::= LP", - /* 305 */ "with ::= WITH wqlist", - /* 306 */ "with ::= WITH RECURSIVE wqlist", - /* 307 */ "wqas ::= AS", - /* 308 */ "wqas ::= AS MATERIALIZED", - /* 309 */ "wqas ::= AS NOT MATERIALIZED", - /* 310 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", - /* 311 */ "withnm ::= nm", - /* 312 */ "wqlist ::= wqitem", - /* 313 */ "wqlist ::= wqlist COMMA wqitem", - /* 314 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", - /* 315 */ "windowdefn ::= nm AS LP window RP", - /* 316 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", - /* 317 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", - /* 318 */ "window ::= ORDER BY sortlist frame_opt", - /* 319 */ "window ::= nm ORDER BY sortlist frame_opt", - /* 320 */ "window ::= nm frame_opt", - /* 321 */ "frame_opt ::=", - /* 322 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", - /* 323 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", - /* 324 */ "range_or_rows ::= RANGE|ROWS|GROUPS", - /* 325 */ "frame_bound_s ::= frame_bound", - /* 326 */ "frame_bound_s ::= UNBOUNDED PRECEDING", - /* 327 */ "frame_bound_e ::= frame_bound", - /* 328 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", - /* 329 */ "frame_bound ::= expr PRECEDING|FOLLOWING", - /* 330 */ "frame_bound ::= CURRENT ROW", - /* 331 */ "frame_exclude_opt ::=", - /* 332 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", - /* 333 */ "frame_exclude ::= NO OTHERS", - /* 334 */ "frame_exclude ::= CURRENT ROW", - /* 335 */ "frame_exclude ::= GROUP|TIES", - /* 336 */ "window_clause ::= WINDOW windowdefn_list", - /* 337 */ "filter_over ::= filter_clause over_clause", - /* 338 */ "filter_over ::= over_clause", - /* 339 */ "filter_over ::= filter_clause", - /* 340 */ "over_clause ::= OVER LP window RP", - /* 341 */ "over_clause ::= OVER nm", - /* 342 */ "filter_clause ::= FILTER LP WHERE expr RP", - /* 343 */ "term ::= QNUMBER", - /* 344 */ "input ::= cmdlist", - /* 345 */ "cmdlist ::= cmdlist ecmd", - /* 346 */ "cmdlist ::= ecmd", - /* 347 */ "ecmd ::= SEMI", - /* 348 */ "ecmd ::= cmdx SEMI", - /* 349 */ "ecmd ::= explain cmdx SEMI", - /* 350 */ "trans_opt ::=", - /* 351 */ "trans_opt ::= TRANSACTION", - /* 352 */ "trans_opt ::= TRANSACTION nm", - /* 353 */ "savepoint_opt ::= SAVEPOINT", - /* 354 */ "savepoint_opt ::=", - /* 355 */ "cmd ::= create_table create_table_args", - /* 356 */ "table_option_set ::= table_option", - /* 357 */ "columnlist ::= columnlist COMMA columnname carglist", - /* 358 */ "columnlist ::= columnname carglist", - /* 359 */ "nm ::= ID|INDEXED|JOIN_KW", - /* 360 */ "nm ::= STRING", - /* 361 */ "typetoken ::= typename", - /* 362 */ "typename ::= ID|STRING", - /* 363 */ "signed ::= plus_num", - /* 364 */ "signed ::= minus_num", - /* 365 */ "carglist ::= carglist ccons", - /* 366 */ "carglist ::=", - /* 367 */ "ccons ::= NULL onconf", - /* 368 */ "ccons ::= GENERATED ALWAYS AS generated", - /* 369 */ "ccons ::= AS generated", - /* 370 */ "conslist_opt ::= COMMA conslist", - /* 371 */ "conslist ::= conslist tconscomma tcons", - /* 372 */ "conslist ::= tcons", - /* 373 */ "tconscomma ::=", - /* 374 */ "defer_subclause_opt ::= defer_subclause", - /* 375 */ "resolvetype ::= raisetype", - /* 376 */ "selectnowith ::= oneselect", - /* 377 */ "oneselect ::= values", - /* 378 */ "sclp ::= selcollist COMMA", - /* 379 */ "as ::= ID|STRING", - /* 380 */ "indexed_opt ::= indexed_by", - /* 381 */ "returning ::=", - /* 382 */ "expr ::= term", - /* 383 */ "likeop ::= LIKE_KW|MATCH", - /* 384 */ "case_operand ::= expr", - /* 385 */ "exprlist ::= nexprlist", - /* 386 */ "nmnum ::= plus_num", - /* 387 */ "nmnum ::= nm", - /* 388 */ "nmnum ::= ON", - /* 389 */ "nmnum ::= DELETE", - /* 390 */ "nmnum ::= DEFAULT", - /* 391 */ "plus_num ::= INTEGER|FLOAT", - /* 392 */ "foreach_clause ::=", - /* 393 */ "foreach_clause ::= FOR EACH ROW", - /* 394 */ "trnm ::= nm", - /* 395 */ "tridxby ::=", - /* 396 */ "database_kw_opt ::= DATABASE", - /* 397 */ "database_kw_opt ::=", - /* 398 */ "kwcolumn_opt ::=", - /* 399 */ "kwcolumn_opt ::= COLUMNKW", - /* 400 */ "vtabarglist ::= vtabarg", - /* 401 */ "vtabarglist ::= vtabarglist COMMA vtabarg", - /* 402 */ "vtabarg ::= vtabarg vtabargtoken", - /* 403 */ "anylist ::=", - /* 404 */ "anylist ::= anylist LP anylist RP", - /* 405 */ "anylist ::= anylist ANY", - /* 406 */ "with ::=", - /* 407 */ "windowdefn_list ::= windowdefn", - /* 408 */ "window ::= frame_opt", + /* 296 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm", + /* 297 */ "cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm", + /* 298 */ "cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL", + /* 299 */ "cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf", + /* 300 */ "cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf", + /* 301 */ "cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf", + /* 302 */ "cmd ::= create_vtab", + /* 303 */ "cmd ::= create_vtab LP vtabarglist RP", + /* 304 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm", + /* 305 */ "vtabarg ::=", + /* 306 */ "vtabargtoken ::= ANY", + /* 307 */ "vtabargtoken ::= lp anylist RP", + /* 308 */ "lp ::= LP", + /* 309 */ "with ::= WITH wqlist", + /* 310 */ "with ::= WITH RECURSIVE wqlist", + /* 311 */ "wqas ::= AS", + /* 312 */ "wqas ::= AS MATERIALIZED", + /* 313 */ "wqas ::= AS NOT MATERIALIZED", + /* 314 */ "wqitem ::= withnm eidlist_opt wqas LP select RP", + /* 315 */ "withnm ::= nm", + /* 316 */ "wqlist ::= wqitem", + /* 317 */ "wqlist ::= wqlist COMMA wqitem", + /* 318 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn", + /* 319 */ "windowdefn ::= nm AS LP window RP", + /* 320 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt", + /* 321 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt", + /* 322 */ "window ::= ORDER BY sortlist frame_opt", + /* 323 */ "window ::= nm ORDER BY sortlist frame_opt", + /* 324 */ "window ::= nm frame_opt", + /* 325 */ "frame_opt ::=", + /* 326 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt", + /* 327 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt", + /* 328 */ "range_or_rows ::= RANGE|ROWS|GROUPS", + /* 329 */ "frame_bound_s ::= frame_bound", + /* 330 */ "frame_bound_s ::= UNBOUNDED PRECEDING", + /* 331 */ "frame_bound_e ::= frame_bound", + /* 332 */ "frame_bound_e ::= UNBOUNDED FOLLOWING", + /* 333 */ "frame_bound ::= expr PRECEDING|FOLLOWING", + /* 334 */ "frame_bound ::= CURRENT ROW", + /* 335 */ "frame_exclude_opt ::=", + /* 336 */ "frame_exclude_opt ::= EXCLUDE frame_exclude", + /* 337 */ "frame_exclude ::= NO OTHERS", + /* 338 */ "frame_exclude ::= CURRENT ROW", + /* 339 */ "frame_exclude ::= GROUP|TIES", + /* 340 */ "window_clause ::= WINDOW windowdefn_list", + /* 341 */ "filter_over ::= filter_clause over_clause", + /* 342 */ "filter_over ::= over_clause", + /* 343 */ "filter_over ::= filter_clause", + /* 344 */ "over_clause ::= OVER LP window RP", + /* 345 */ "over_clause ::= OVER nm", + /* 346 */ "filter_clause ::= FILTER LP WHERE expr RP", + /* 347 */ "term ::= QNUMBER", + /* 348 */ "input ::= cmdlist", + /* 349 */ "cmdlist ::= cmdlist ecmd", + /* 350 */ "cmdlist ::= ecmd", + /* 351 */ "ecmd ::= SEMI", + /* 352 */ "ecmd ::= cmdx SEMI", + /* 353 */ "ecmd ::= explain cmdx SEMI", + /* 354 */ "trans_opt ::=", + /* 355 */ "trans_opt ::= TRANSACTION", + /* 356 */ "trans_opt ::= TRANSACTION nm", + /* 357 */ "savepoint_opt ::= SAVEPOINT", + /* 358 */ "savepoint_opt ::=", + /* 359 */ "cmd ::= create_table create_table_args", + /* 360 */ "table_option_set ::= table_option", + /* 361 */ "columnlist ::= columnlist COMMA columnname carglist", + /* 362 */ "columnlist ::= columnname carglist", + /* 363 */ "nm ::= ID|INDEXED|JOIN_KW", + /* 364 */ "nm ::= STRING", + /* 365 */ "typetoken ::= typename", + /* 366 */ "typename ::= ID|STRING", + /* 367 */ "signed ::= plus_num", + /* 368 */ "signed ::= minus_num", + /* 369 */ "carglist ::= carglist ccons", + /* 370 */ "carglist ::=", + /* 371 */ "ccons ::= NULL onconf", + /* 372 */ "ccons ::= GENERATED ALWAYS AS generated", + /* 373 */ "ccons ::= AS generated", + /* 374 */ "conslist_opt ::= COMMA conslist", + /* 375 */ "conslist ::= conslist tconscomma tcons", + /* 376 */ "conslist ::= tcons", + /* 377 */ "tconscomma ::=", + /* 378 */ "defer_subclause_opt ::= defer_subclause", + /* 379 */ "resolvetype ::= raisetype", + /* 380 */ "selectnowith ::= oneselect", + /* 381 */ "oneselect ::= values", + /* 382 */ "sclp ::= selcollist COMMA", + /* 383 */ "as ::= ID|STRING", + /* 384 */ "indexed_opt ::= indexed_by", + /* 385 */ "returning ::=", + /* 386 */ "expr ::= term", + /* 387 */ "likeop ::= LIKE_KW|MATCH", + /* 388 */ "case_operand ::= expr", + /* 389 */ "exprlist ::= nexprlist", + /* 390 */ "nmnum ::= plus_num", + /* 391 */ "nmnum ::= nm", + /* 392 */ "nmnum ::= ON", + /* 393 */ "nmnum ::= DELETE", + /* 394 */ "nmnum ::= DEFAULT", + /* 395 */ "plus_num ::= INTEGER|FLOAT", + /* 396 */ "foreach_clause ::=", + /* 397 */ "foreach_clause ::= FOR EACH ROW", + /* 398 */ "tridxby ::=", + /* 399 */ "database_kw_opt ::= DATABASE", + /* 400 */ "database_kw_opt ::=", + /* 401 */ "kwcolumn_opt ::=", + /* 402 */ "kwcolumn_opt ::= COLUMNKW", + /* 403 */ "vtabarglist ::= vtabarg", + /* 404 */ "vtabarglist ::= vtabarglist COMMA vtabarg", + /* 405 */ "vtabarg ::= vtabarg vtabargtoken", + /* 406 */ "anylist ::=", + /* 407 */ "anylist ::= anylist LP anylist RP", + /* 408 */ "anylist ::= anylist ANY", + /* 409 */ "with ::=", + /* 410 */ "windowdefn_list ::= windowdefn", + /* 411 */ "window ::= frame_opt", }; #endif /* NDEBUG */ @@ -179834,15 +181976,24 @@ static int yyGrowStack(yyParser *p){ int newSize; int idx; yyStackEntry *pNew; +#ifdef YYSIZELIMIT + int nLimit = YYSIZELIMIT(sqlite3ParserCTX(p)); +#endif newSize = oldSize*2 + 100; +#ifdef YYSIZELIMIT + if( newSize>nLimit ){ + newSize = nLimit; + if( newSize<=oldSize ) return 1; + } +#endif idx = (int)(p->yytos - p->yystack); if( p->yystack==p->yystk0 ){ - pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(0, newSize*sizeof(pNew[0]), sqlite3ParserCTX(p)); if( pNew==0 ) return 1; memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0]), sqlite3ParserCTX(p)); if( pNew==0 ) return 1; } p->yystack = pNew; @@ -179949,7 +182100,7 @@ static void yy_destructor( case 254: /* values */ case 256: /* mvalues */ { -sqlite3SelectDelete(pParse->db, (yypminor->yy637)); +sqlite3SelectDelete(pParse->db, (yypminor->yy555)); } break; case 218: /* term */ @@ -179961,10 +182112,10 @@ sqlite3SelectDelete(pParse->db, (yypminor->yy637)); case 283: /* case_else */ case 286: /* vinto */ case 293: /* when_clause */ - case 298: /* key_opt */ - case 315: /* filter_clause */ + case 297: /* key_opt */ + case 314: /* filter_clause */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy590)); +sqlite3ExprDelete(pParse->db, (yypminor->yy454)); } break; case 223: /* eidlist_opt */ @@ -179979,9 +182130,9 @@ sqlite3ExprDelete(pParse->db, (yypminor->yy590)); case 271: /* setlist */ case 280: /* paren_exprlist */ case 282: /* case_exprlist */ - case 314: /* part_opt */ + case 313: /* part_opt */ { -sqlite3ExprListDelete(pParse->db, (yypminor->yy402)); +sqlite3ExprListDelete(pParse->db, (yypminor->yy14)); } break; case 240: /* fullname */ @@ -179990,51 +182141,51 @@ sqlite3ExprListDelete(pParse->db, (yypminor->yy402)); case 260: /* stl_prefix */ case 265: /* xfullname */ { -sqlite3SrcListDelete(pParse->db, (yypminor->yy563)); +sqlite3SrcListDelete(pParse->db, (yypminor->yy203)); } break; case 243: /* wqlist */ { -sqlite3WithDelete(pParse->db, (yypminor->yy125)); +sqlite3WithDelete(pParse->db, (yypminor->yy59)); } break; case 253: /* window_clause */ - case 310: /* windowdefn_list */ + case 309: /* windowdefn_list */ { -sqlite3WindowListDelete(pParse->db, (yypminor->yy483)); +sqlite3WindowListDelete(pParse->db, (yypminor->yy211)); } break; case 266: /* idlist */ case 273: /* idlist_opt */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy204)); +sqlite3IdListDelete(pParse->db, (yypminor->yy132)); } break; case 276: /* filter_over */ - case 311: /* windowdefn */ - case 312: /* window */ - case 313: /* frame_opt */ - case 316: /* over_clause */ + case 310: /* windowdefn */ + case 311: /* window */ + case 312: /* frame_opt */ + case 315: /* over_clause */ { -sqlite3WindowDelete(pParse->db, (yypminor->yy483)); +sqlite3WindowDelete(pParse->db, (yypminor->yy211)); } break; case 289: /* trigger_cmd_list */ case 294: /* trigger_cmd */ { -sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy319)); +sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427)); } break; case 291: /* trigger_event */ { -sqlite3IdListDelete(pParse->db, (yypminor->yy28).b); +sqlite3IdListDelete(pParse->db, (yypminor->yy286).b); } break; - case 318: /* frame_bound */ - case 319: /* frame_bound_s */ - case 320: /* frame_bound_e */ + case 317: /* frame_bound */ + case 318: /* frame_bound_s */ + case 319: /* frame_bound_e */ { -sqlite3ExprDelete(pParse->db, (yypminor->yy205).pExpr); +sqlite3ExprDelete(pParse->db, (yypminor->yy509).pExpr); } break; /********* End destructor definitions *****************************************/ @@ -180087,7 +182238,9 @@ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){ } #if YYGROWABLESTACK - if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack); + if( pParser->yystack!=pParser->yystk0 ){ + YYFREE(pParser->yystack, sqlite3ParserCTX(pParser)); + } #endif } @@ -180270,7 +182423,7 @@ static void yyStackOverflow(yyParser *yypParser){ ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ - sqlite3OomFault(pParse->db); + if( pParse->nErr==0 ) sqlite3ErrorMsg(pParse, "Recursion limit"); /******** End %stack_overflow code ********************************************/ sqlite3ParserARG_STORE /* Suppress warning about unused %extra_argument var */ sqlite3ParserCTX_STORE @@ -180458,8 +182611,8 @@ static const YYCODETYPE yyRuleInfoLhs[] = { 240, /* (119) fullname ::= nm DOT nm */ 265, /* (120) xfullname ::= nm */ 265, /* (121) xfullname ::= nm DOT nm */ - 265, /* (122) xfullname ::= nm DOT nm AS nm */ - 265, /* (123) xfullname ::= nm AS nm */ + 265, /* (122) xfullname ::= nm AS nm */ + 265, /* (123) xfullname ::= nm DOT nm AS nm */ 261, /* (124) joinop ::= COMMA|JOIN */ 261, /* (125) joinop ::= JOIN_KW JOIN */ 261, /* (126) joinop ::= JOIN_KW nm JOIN */ @@ -180608,143 +182761,146 @@ static const YYCODETYPE yyRuleInfoLhs[] = { 293, /* (269) when_clause ::= WHEN expr */ 289, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ 289, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - 295, /* (272) trnm ::= nm DOT nm */ - 296, /* (273) tridxby ::= INDEXED BY nm */ - 296, /* (274) tridxby ::= NOT INDEXED */ - 294, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - 294, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - 294, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - 294, /* (278) trigger_cmd ::= scanpt select scanpt */ - 219, /* (279) expr ::= RAISE LP IGNORE RP */ - 219, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - 238, /* (281) raisetype ::= ROLLBACK */ - 238, /* (282) raisetype ::= ABORT */ - 238, /* (283) raisetype ::= FAIL */ - 192, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - 192, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - 192, /* (286) cmd ::= DETACH database_kw_opt expr */ - 298, /* (287) key_opt ::= */ - 298, /* (288) key_opt ::= KEY expr */ - 192, /* (289) cmd ::= REINDEX */ - 192, /* (290) cmd ::= REINDEX nm dbnm */ - 192, /* (291) cmd ::= ANALYZE */ - 192, /* (292) cmd ::= ANALYZE nm dbnm */ - 192, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - 192, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + 295, /* (272) tridxby ::= INDEXED BY nm */ + 295, /* (273) tridxby ::= NOT INDEXED */ + 294, /* (274) trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ + 294, /* (275) trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ + 294, /* (276) trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ + 294, /* (277) trigger_cmd ::= scanpt select scanpt */ + 219, /* (278) expr ::= RAISE LP IGNORE RP */ + 219, /* (279) expr ::= RAISE LP raisetype COMMA expr RP */ + 238, /* (280) raisetype ::= ROLLBACK */ + 238, /* (281) raisetype ::= ABORT */ + 238, /* (282) raisetype ::= FAIL */ + 192, /* (283) cmd ::= DROP TRIGGER ifexists fullname */ + 192, /* (284) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + 192, /* (285) cmd ::= DETACH database_kw_opt expr */ + 297, /* (286) key_opt ::= */ + 297, /* (287) key_opt ::= KEY expr */ + 192, /* (288) cmd ::= REINDEX */ + 192, /* (289) cmd ::= REINDEX nm dbnm */ + 192, /* (290) cmd ::= ANALYZE */ + 192, /* (291) cmd ::= ANALYZE nm dbnm */ + 192, /* (292) cmd ::= ALTER TABLE fullname RENAME TO nm */ + 192, /* (293) cmd ::= alter_add carglist */ + 298, /* (294) alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ 192, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - 299, /* (296) add_column_fullname ::= fullname */ - 192, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - 192, /* (298) cmd ::= create_vtab */ - 192, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - 301, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 303, /* (301) vtabarg ::= */ - 304, /* (302) vtabargtoken ::= ANY */ - 304, /* (303) vtabargtoken ::= lp anylist RP */ - 305, /* (304) lp ::= LP */ - 269, /* (305) with ::= WITH wqlist */ - 269, /* (306) with ::= WITH RECURSIVE wqlist */ - 308, /* (307) wqas ::= AS */ - 308, /* (308) wqas ::= AS MATERIALIZED */ - 308, /* (309) wqas ::= AS NOT MATERIALIZED */ - 307, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - 309, /* (311) withnm ::= nm */ - 243, /* (312) wqlist ::= wqitem */ - 243, /* (313) wqlist ::= wqlist COMMA wqitem */ - 310, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - 311, /* (315) windowdefn ::= nm AS LP window RP */ - 312, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - 312, /* (318) window ::= ORDER BY sortlist frame_opt */ - 312, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - 312, /* (320) window ::= nm frame_opt */ - 313, /* (321) frame_opt ::= */ - 313, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - 313, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - 317, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - 319, /* (325) frame_bound_s ::= frame_bound */ - 319, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - 320, /* (327) frame_bound_e ::= frame_bound */ - 320, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - 318, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - 318, /* (330) frame_bound ::= CURRENT ROW */ - 321, /* (331) frame_exclude_opt ::= */ - 321, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - 322, /* (333) frame_exclude ::= NO OTHERS */ - 322, /* (334) frame_exclude ::= CURRENT ROW */ - 322, /* (335) frame_exclude ::= GROUP|TIES */ - 253, /* (336) window_clause ::= WINDOW windowdefn_list */ - 276, /* (337) filter_over ::= filter_clause over_clause */ - 276, /* (338) filter_over ::= over_clause */ - 276, /* (339) filter_over ::= filter_clause */ - 316, /* (340) over_clause ::= OVER LP window RP */ - 316, /* (341) over_clause ::= OVER nm */ - 315, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - 218, /* (343) term ::= QNUMBER */ - 187, /* (344) input ::= cmdlist */ - 188, /* (345) cmdlist ::= cmdlist ecmd */ - 188, /* (346) cmdlist ::= ecmd */ - 189, /* (347) ecmd ::= SEMI */ - 189, /* (348) ecmd ::= cmdx SEMI */ - 189, /* (349) ecmd ::= explain cmdx SEMI */ - 194, /* (350) trans_opt ::= */ - 194, /* (351) trans_opt ::= TRANSACTION */ - 194, /* (352) trans_opt ::= TRANSACTION nm */ - 196, /* (353) savepoint_opt ::= SAVEPOINT */ - 196, /* (354) savepoint_opt ::= */ - 192, /* (355) cmd ::= create_table create_table_args */ - 205, /* (356) table_option_set ::= table_option */ - 203, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - 203, /* (358) columnlist ::= columnname carglist */ - 195, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - 195, /* (360) nm ::= STRING */ - 210, /* (361) typetoken ::= typename */ - 211, /* (362) typename ::= ID|STRING */ - 212, /* (363) signed ::= plus_num */ - 212, /* (364) signed ::= minus_num */ - 209, /* (365) carglist ::= carglist ccons */ - 209, /* (366) carglist ::= */ - 217, /* (367) ccons ::= NULL onconf */ - 217, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - 217, /* (369) ccons ::= AS generated */ - 204, /* (370) conslist_opt ::= COMMA conslist */ - 230, /* (371) conslist ::= conslist tconscomma tcons */ - 230, /* (372) conslist ::= tcons */ - 231, /* (373) tconscomma ::= */ - 235, /* (374) defer_subclause_opt ::= defer_subclause */ - 237, /* (375) resolvetype ::= raisetype */ - 241, /* (376) selectnowith ::= oneselect */ - 242, /* (377) oneselect ::= values */ - 257, /* (378) sclp ::= selcollist COMMA */ - 258, /* (379) as ::= ID|STRING */ - 267, /* (380) indexed_opt ::= indexed_by */ - 275, /* (381) returning ::= */ - 219, /* (382) expr ::= term */ - 277, /* (383) likeop ::= LIKE_KW|MATCH */ - 281, /* (384) case_operand ::= expr */ - 264, /* (385) exprlist ::= nexprlist */ - 287, /* (386) nmnum ::= plus_num */ - 287, /* (387) nmnum ::= nm */ - 287, /* (388) nmnum ::= ON */ - 287, /* (389) nmnum ::= DELETE */ - 287, /* (390) nmnum ::= DEFAULT */ - 213, /* (391) plus_num ::= INTEGER|FLOAT */ - 292, /* (392) foreach_clause ::= */ - 292, /* (393) foreach_clause ::= FOR EACH ROW */ - 295, /* (394) trnm ::= nm */ - 296, /* (395) tridxby ::= */ - 297, /* (396) database_kw_opt ::= DATABASE */ - 297, /* (397) database_kw_opt ::= */ - 300, /* (398) kwcolumn_opt ::= */ - 300, /* (399) kwcolumn_opt ::= COLUMNKW */ - 302, /* (400) vtabarglist ::= vtabarg */ - 302, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - 303, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 306, /* (403) anylist ::= */ - 306, /* (404) anylist ::= anylist LP anylist RP */ - 306, /* (405) anylist ::= anylist ANY */ - 269, /* (406) with ::= */ - 310, /* (407) windowdefn_list ::= windowdefn */ - 312, /* (408) window ::= frame_opt */ + 192, /* (296) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + 192, /* (297) cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ + 192, /* (298) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ + 192, /* (299) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ + 192, /* (300) cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ + 192, /* (301) cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ + 192, /* (302) cmd ::= create_vtab */ + 192, /* (303) cmd ::= create_vtab LP vtabarglist RP */ + 300, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 302, /* (305) vtabarg ::= */ + 303, /* (306) vtabargtoken ::= ANY */ + 303, /* (307) vtabargtoken ::= lp anylist RP */ + 304, /* (308) lp ::= LP */ + 269, /* (309) with ::= WITH wqlist */ + 269, /* (310) with ::= WITH RECURSIVE wqlist */ + 307, /* (311) wqas ::= AS */ + 307, /* (312) wqas ::= AS MATERIALIZED */ + 307, /* (313) wqas ::= AS NOT MATERIALIZED */ + 306, /* (314) wqitem ::= withnm eidlist_opt wqas LP select RP */ + 308, /* (315) withnm ::= nm */ + 243, /* (316) wqlist ::= wqitem */ + 243, /* (317) wqlist ::= wqlist COMMA wqitem */ + 309, /* (318) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + 310, /* (319) windowdefn ::= nm AS LP window RP */ + 311, /* (320) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + 311, /* (321) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + 311, /* (322) window ::= ORDER BY sortlist frame_opt */ + 311, /* (323) window ::= nm ORDER BY sortlist frame_opt */ + 311, /* (324) window ::= nm frame_opt */ + 312, /* (325) frame_opt ::= */ + 312, /* (326) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + 312, /* (327) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + 316, /* (328) range_or_rows ::= RANGE|ROWS|GROUPS */ + 318, /* (329) frame_bound_s ::= frame_bound */ + 318, /* (330) frame_bound_s ::= UNBOUNDED PRECEDING */ + 319, /* (331) frame_bound_e ::= frame_bound */ + 319, /* (332) frame_bound_e ::= UNBOUNDED FOLLOWING */ + 317, /* (333) frame_bound ::= expr PRECEDING|FOLLOWING */ + 317, /* (334) frame_bound ::= CURRENT ROW */ + 320, /* (335) frame_exclude_opt ::= */ + 320, /* (336) frame_exclude_opt ::= EXCLUDE frame_exclude */ + 321, /* (337) frame_exclude ::= NO OTHERS */ + 321, /* (338) frame_exclude ::= CURRENT ROW */ + 321, /* (339) frame_exclude ::= GROUP|TIES */ + 253, /* (340) window_clause ::= WINDOW windowdefn_list */ + 276, /* (341) filter_over ::= filter_clause over_clause */ + 276, /* (342) filter_over ::= over_clause */ + 276, /* (343) filter_over ::= filter_clause */ + 315, /* (344) over_clause ::= OVER LP window RP */ + 315, /* (345) over_clause ::= OVER nm */ + 314, /* (346) filter_clause ::= FILTER LP WHERE expr RP */ + 218, /* (347) term ::= QNUMBER */ + 187, /* (348) input ::= cmdlist */ + 188, /* (349) cmdlist ::= cmdlist ecmd */ + 188, /* (350) cmdlist ::= ecmd */ + 189, /* (351) ecmd ::= SEMI */ + 189, /* (352) ecmd ::= cmdx SEMI */ + 189, /* (353) ecmd ::= explain cmdx SEMI */ + 194, /* (354) trans_opt ::= */ + 194, /* (355) trans_opt ::= TRANSACTION */ + 194, /* (356) trans_opt ::= TRANSACTION nm */ + 196, /* (357) savepoint_opt ::= SAVEPOINT */ + 196, /* (358) savepoint_opt ::= */ + 192, /* (359) cmd ::= create_table create_table_args */ + 205, /* (360) table_option_set ::= table_option */ + 203, /* (361) columnlist ::= columnlist COMMA columnname carglist */ + 203, /* (362) columnlist ::= columnname carglist */ + 195, /* (363) nm ::= ID|INDEXED|JOIN_KW */ + 195, /* (364) nm ::= STRING */ + 210, /* (365) typetoken ::= typename */ + 211, /* (366) typename ::= ID|STRING */ + 212, /* (367) signed ::= plus_num */ + 212, /* (368) signed ::= minus_num */ + 209, /* (369) carglist ::= carglist ccons */ + 209, /* (370) carglist ::= */ + 217, /* (371) ccons ::= NULL onconf */ + 217, /* (372) ccons ::= GENERATED ALWAYS AS generated */ + 217, /* (373) ccons ::= AS generated */ + 204, /* (374) conslist_opt ::= COMMA conslist */ + 230, /* (375) conslist ::= conslist tconscomma tcons */ + 230, /* (376) conslist ::= tcons */ + 231, /* (377) tconscomma ::= */ + 235, /* (378) defer_subclause_opt ::= defer_subclause */ + 237, /* (379) resolvetype ::= raisetype */ + 241, /* (380) selectnowith ::= oneselect */ + 242, /* (381) oneselect ::= values */ + 257, /* (382) sclp ::= selcollist COMMA */ + 258, /* (383) as ::= ID|STRING */ + 267, /* (384) indexed_opt ::= indexed_by */ + 275, /* (385) returning ::= */ + 219, /* (386) expr ::= term */ + 277, /* (387) likeop ::= LIKE_KW|MATCH */ + 281, /* (388) case_operand ::= expr */ + 264, /* (389) exprlist ::= nexprlist */ + 287, /* (390) nmnum ::= plus_num */ + 287, /* (391) nmnum ::= nm */ + 287, /* (392) nmnum ::= ON */ + 287, /* (393) nmnum ::= DELETE */ + 287, /* (394) nmnum ::= DEFAULT */ + 213, /* (395) plus_num ::= INTEGER|FLOAT */ + 292, /* (396) foreach_clause ::= */ + 292, /* (397) foreach_clause ::= FOR EACH ROW */ + 295, /* (398) tridxby ::= */ + 296, /* (399) database_kw_opt ::= DATABASE */ + 296, /* (400) database_kw_opt ::= */ + 299, /* (401) kwcolumn_opt ::= */ + 299, /* (402) kwcolumn_opt ::= COLUMNKW */ + 301, /* (403) vtabarglist ::= vtabarg */ + 301, /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ + 302, /* (405) vtabarg ::= vtabarg vtabargtoken */ + 305, /* (406) anylist ::= */ + 305, /* (407) anylist ::= anylist LP anylist RP */ + 305, /* (408) anylist ::= anylist ANY */ + 269, /* (409) with ::= */ + 309, /* (410) windowdefn_list ::= windowdefn */ + 311, /* (411) window ::= frame_opt */ }; /* For rule J, yyRuleInfoNRhs[J] contains the negative of the number @@ -180872,8 +183028,8 @@ static const signed char yyRuleInfoNRhs[] = { -3, /* (119) fullname ::= nm DOT nm */ -1, /* (120) xfullname ::= nm */ -3, /* (121) xfullname ::= nm DOT nm */ - -5, /* (122) xfullname ::= nm DOT nm AS nm */ - -3, /* (123) xfullname ::= nm AS nm */ + -3, /* (122) xfullname ::= nm AS nm */ + -5, /* (123) xfullname ::= nm DOT nm AS nm */ -1, /* (124) joinop ::= COMMA|JOIN */ -2, /* (125) joinop ::= JOIN_KW JOIN */ -3, /* (126) joinop ::= JOIN_KW nm JOIN */ @@ -181022,143 +183178,146 @@ static const signed char yyRuleInfoNRhs[] = { -2, /* (269) when_clause ::= WHEN expr */ -3, /* (270) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ -2, /* (271) trigger_cmd_list ::= trigger_cmd SEMI */ - -3, /* (272) trnm ::= nm DOT nm */ - -3, /* (273) tridxby ::= INDEXED BY nm */ - -2, /* (274) tridxby ::= NOT INDEXED */ - -9, /* (275) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ - -8, /* (276) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ - -6, /* (277) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ - -3, /* (278) trigger_cmd ::= scanpt select scanpt */ - -4, /* (279) expr ::= RAISE LP IGNORE RP */ - -6, /* (280) expr ::= RAISE LP raisetype COMMA expr RP */ - -1, /* (281) raisetype ::= ROLLBACK */ - -1, /* (282) raisetype ::= ABORT */ - -1, /* (283) raisetype ::= FAIL */ - -4, /* (284) cmd ::= DROP TRIGGER ifexists fullname */ - -6, /* (285) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ - -3, /* (286) cmd ::= DETACH database_kw_opt expr */ - 0, /* (287) key_opt ::= */ - -2, /* (288) key_opt ::= KEY expr */ - -1, /* (289) cmd ::= REINDEX */ - -3, /* (290) cmd ::= REINDEX nm dbnm */ - -1, /* (291) cmd ::= ANALYZE */ - -3, /* (292) cmd ::= ANALYZE nm dbnm */ - -6, /* (293) cmd ::= ALTER TABLE fullname RENAME TO nm */ - -7, /* (294) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + -3, /* (272) tridxby ::= INDEXED BY nm */ + -2, /* (273) tridxby ::= NOT INDEXED */ + -9, /* (274) trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ + -8, /* (275) trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ + -6, /* (276) trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ + -3, /* (277) trigger_cmd ::= scanpt select scanpt */ + -4, /* (278) expr ::= RAISE LP IGNORE RP */ + -6, /* (279) expr ::= RAISE LP raisetype COMMA expr RP */ + -1, /* (280) raisetype ::= ROLLBACK */ + -1, /* (281) raisetype ::= ABORT */ + -1, /* (282) raisetype ::= FAIL */ + -4, /* (283) cmd ::= DROP TRIGGER ifexists fullname */ + -6, /* (284) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + -3, /* (285) cmd ::= DETACH database_kw_opt expr */ + 0, /* (286) key_opt ::= */ + -2, /* (287) key_opt ::= KEY expr */ + -1, /* (288) cmd ::= REINDEX */ + -3, /* (289) cmd ::= REINDEX nm dbnm */ + -1, /* (290) cmd ::= ANALYZE */ + -3, /* (291) cmd ::= ANALYZE nm dbnm */ + -6, /* (292) cmd ::= ALTER TABLE fullname RENAME TO nm */ + -2, /* (293) cmd ::= alter_add carglist */ + -7, /* (294) alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ -6, /* (295) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ - -1, /* (296) add_column_fullname ::= fullname */ - -8, /* (297) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ - -1, /* (298) cmd ::= create_vtab */ - -4, /* (299) cmd ::= create_vtab LP vtabarglist RP */ - -8, /* (300) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ - 0, /* (301) vtabarg ::= */ - -1, /* (302) vtabargtoken ::= ANY */ - -3, /* (303) vtabargtoken ::= lp anylist RP */ - -1, /* (304) lp ::= LP */ - -2, /* (305) with ::= WITH wqlist */ - -3, /* (306) with ::= WITH RECURSIVE wqlist */ - -1, /* (307) wqas ::= AS */ - -2, /* (308) wqas ::= AS MATERIALIZED */ - -3, /* (309) wqas ::= AS NOT MATERIALIZED */ - -6, /* (310) wqitem ::= withnm eidlist_opt wqas LP select RP */ - -1, /* (311) withnm ::= nm */ - -1, /* (312) wqlist ::= wqitem */ - -3, /* (313) wqlist ::= wqlist COMMA wqitem */ - -3, /* (314) windowdefn_list ::= windowdefn_list COMMA windowdefn */ - -5, /* (315) windowdefn ::= nm AS LP window RP */ - -5, /* (316) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ - -6, /* (317) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ - -4, /* (318) window ::= ORDER BY sortlist frame_opt */ - -5, /* (319) window ::= nm ORDER BY sortlist frame_opt */ - -2, /* (320) window ::= nm frame_opt */ - 0, /* (321) frame_opt ::= */ - -3, /* (322) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ - -6, /* (323) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ - -1, /* (324) range_or_rows ::= RANGE|ROWS|GROUPS */ - -1, /* (325) frame_bound_s ::= frame_bound */ - -2, /* (326) frame_bound_s ::= UNBOUNDED PRECEDING */ - -1, /* (327) frame_bound_e ::= frame_bound */ - -2, /* (328) frame_bound_e ::= UNBOUNDED FOLLOWING */ - -2, /* (329) frame_bound ::= expr PRECEDING|FOLLOWING */ - -2, /* (330) frame_bound ::= CURRENT ROW */ - 0, /* (331) frame_exclude_opt ::= */ - -2, /* (332) frame_exclude_opt ::= EXCLUDE frame_exclude */ - -2, /* (333) frame_exclude ::= NO OTHERS */ - -2, /* (334) frame_exclude ::= CURRENT ROW */ - -1, /* (335) frame_exclude ::= GROUP|TIES */ - -2, /* (336) window_clause ::= WINDOW windowdefn_list */ - -2, /* (337) filter_over ::= filter_clause over_clause */ - -1, /* (338) filter_over ::= over_clause */ - -1, /* (339) filter_over ::= filter_clause */ - -4, /* (340) over_clause ::= OVER LP window RP */ - -2, /* (341) over_clause ::= OVER nm */ - -5, /* (342) filter_clause ::= FILTER LP WHERE expr RP */ - -1, /* (343) term ::= QNUMBER */ - -1, /* (344) input ::= cmdlist */ - -2, /* (345) cmdlist ::= cmdlist ecmd */ - -1, /* (346) cmdlist ::= ecmd */ - -1, /* (347) ecmd ::= SEMI */ - -2, /* (348) ecmd ::= cmdx SEMI */ - -3, /* (349) ecmd ::= explain cmdx SEMI */ - 0, /* (350) trans_opt ::= */ - -1, /* (351) trans_opt ::= TRANSACTION */ - -2, /* (352) trans_opt ::= TRANSACTION nm */ - -1, /* (353) savepoint_opt ::= SAVEPOINT */ - 0, /* (354) savepoint_opt ::= */ - -2, /* (355) cmd ::= create_table create_table_args */ - -1, /* (356) table_option_set ::= table_option */ - -4, /* (357) columnlist ::= columnlist COMMA columnname carglist */ - -2, /* (358) columnlist ::= columnname carglist */ - -1, /* (359) nm ::= ID|INDEXED|JOIN_KW */ - -1, /* (360) nm ::= STRING */ - -1, /* (361) typetoken ::= typename */ - -1, /* (362) typename ::= ID|STRING */ - -1, /* (363) signed ::= plus_num */ - -1, /* (364) signed ::= minus_num */ - -2, /* (365) carglist ::= carglist ccons */ - 0, /* (366) carglist ::= */ - -2, /* (367) ccons ::= NULL onconf */ - -4, /* (368) ccons ::= GENERATED ALWAYS AS generated */ - -2, /* (369) ccons ::= AS generated */ - -2, /* (370) conslist_opt ::= COMMA conslist */ - -3, /* (371) conslist ::= conslist tconscomma tcons */ - -1, /* (372) conslist ::= tcons */ - 0, /* (373) tconscomma ::= */ - -1, /* (374) defer_subclause_opt ::= defer_subclause */ - -1, /* (375) resolvetype ::= raisetype */ - -1, /* (376) selectnowith ::= oneselect */ - -1, /* (377) oneselect ::= values */ - -2, /* (378) sclp ::= selcollist COMMA */ - -1, /* (379) as ::= ID|STRING */ - -1, /* (380) indexed_opt ::= indexed_by */ - 0, /* (381) returning ::= */ - -1, /* (382) expr ::= term */ - -1, /* (383) likeop ::= LIKE_KW|MATCH */ - -1, /* (384) case_operand ::= expr */ - -1, /* (385) exprlist ::= nexprlist */ - -1, /* (386) nmnum ::= plus_num */ - -1, /* (387) nmnum ::= nm */ - -1, /* (388) nmnum ::= ON */ - -1, /* (389) nmnum ::= DELETE */ - -1, /* (390) nmnum ::= DEFAULT */ - -1, /* (391) plus_num ::= INTEGER|FLOAT */ - 0, /* (392) foreach_clause ::= */ - -3, /* (393) foreach_clause ::= FOR EACH ROW */ - -1, /* (394) trnm ::= nm */ - 0, /* (395) tridxby ::= */ - -1, /* (396) database_kw_opt ::= DATABASE */ - 0, /* (397) database_kw_opt ::= */ - 0, /* (398) kwcolumn_opt ::= */ - -1, /* (399) kwcolumn_opt ::= COLUMNKW */ - -1, /* (400) vtabarglist ::= vtabarg */ - -3, /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ - -2, /* (402) vtabarg ::= vtabarg vtabargtoken */ - 0, /* (403) anylist ::= */ - -4, /* (404) anylist ::= anylist LP anylist RP */ - -2, /* (405) anylist ::= anylist ANY */ - 0, /* (406) with ::= */ - -1, /* (407) windowdefn_list ::= windowdefn */ - -1, /* (408) window ::= frame_opt */ + -8, /* (296) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + -6, /* (297) cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ + -9, /* (298) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ + -10, /* (299) cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ + -11, /* (300) cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ + -9, /* (301) cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ + -1, /* (302) cmd ::= create_vtab */ + -4, /* (303) cmd ::= create_vtab LP vtabarglist RP */ + -8, /* (304) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + 0, /* (305) vtabarg ::= */ + -1, /* (306) vtabargtoken ::= ANY */ + -3, /* (307) vtabargtoken ::= lp anylist RP */ + -1, /* (308) lp ::= LP */ + -2, /* (309) with ::= WITH wqlist */ + -3, /* (310) with ::= WITH RECURSIVE wqlist */ + -1, /* (311) wqas ::= AS */ + -2, /* (312) wqas ::= AS MATERIALIZED */ + -3, /* (313) wqas ::= AS NOT MATERIALIZED */ + -6, /* (314) wqitem ::= withnm eidlist_opt wqas LP select RP */ + -1, /* (315) withnm ::= nm */ + -1, /* (316) wqlist ::= wqitem */ + -3, /* (317) wqlist ::= wqlist COMMA wqitem */ + -3, /* (318) windowdefn_list ::= windowdefn_list COMMA windowdefn */ + -5, /* (319) windowdefn ::= nm AS LP window RP */ + -5, /* (320) window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + -6, /* (321) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + -4, /* (322) window ::= ORDER BY sortlist frame_opt */ + -5, /* (323) window ::= nm ORDER BY sortlist frame_opt */ + -2, /* (324) window ::= nm frame_opt */ + 0, /* (325) frame_opt ::= */ + -3, /* (326) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + -6, /* (327) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + -1, /* (328) range_or_rows ::= RANGE|ROWS|GROUPS */ + -1, /* (329) frame_bound_s ::= frame_bound */ + -2, /* (330) frame_bound_s ::= UNBOUNDED PRECEDING */ + -1, /* (331) frame_bound_e ::= frame_bound */ + -2, /* (332) frame_bound_e ::= UNBOUNDED FOLLOWING */ + -2, /* (333) frame_bound ::= expr PRECEDING|FOLLOWING */ + -2, /* (334) frame_bound ::= CURRENT ROW */ + 0, /* (335) frame_exclude_opt ::= */ + -2, /* (336) frame_exclude_opt ::= EXCLUDE frame_exclude */ + -2, /* (337) frame_exclude ::= NO OTHERS */ + -2, /* (338) frame_exclude ::= CURRENT ROW */ + -1, /* (339) frame_exclude ::= GROUP|TIES */ + -2, /* (340) window_clause ::= WINDOW windowdefn_list */ + -2, /* (341) filter_over ::= filter_clause over_clause */ + -1, /* (342) filter_over ::= over_clause */ + -1, /* (343) filter_over ::= filter_clause */ + -4, /* (344) over_clause ::= OVER LP window RP */ + -2, /* (345) over_clause ::= OVER nm */ + -5, /* (346) filter_clause ::= FILTER LP WHERE expr RP */ + -1, /* (347) term ::= QNUMBER */ + -1, /* (348) input ::= cmdlist */ + -2, /* (349) cmdlist ::= cmdlist ecmd */ + -1, /* (350) cmdlist ::= ecmd */ + -1, /* (351) ecmd ::= SEMI */ + -2, /* (352) ecmd ::= cmdx SEMI */ + -3, /* (353) ecmd ::= explain cmdx SEMI */ + 0, /* (354) trans_opt ::= */ + -1, /* (355) trans_opt ::= TRANSACTION */ + -2, /* (356) trans_opt ::= TRANSACTION nm */ + -1, /* (357) savepoint_opt ::= SAVEPOINT */ + 0, /* (358) savepoint_opt ::= */ + -2, /* (359) cmd ::= create_table create_table_args */ + -1, /* (360) table_option_set ::= table_option */ + -4, /* (361) columnlist ::= columnlist COMMA columnname carglist */ + -2, /* (362) columnlist ::= columnname carglist */ + -1, /* (363) nm ::= ID|INDEXED|JOIN_KW */ + -1, /* (364) nm ::= STRING */ + -1, /* (365) typetoken ::= typename */ + -1, /* (366) typename ::= ID|STRING */ + -1, /* (367) signed ::= plus_num */ + -1, /* (368) signed ::= minus_num */ + -2, /* (369) carglist ::= carglist ccons */ + 0, /* (370) carglist ::= */ + -2, /* (371) ccons ::= NULL onconf */ + -4, /* (372) ccons ::= GENERATED ALWAYS AS generated */ + -2, /* (373) ccons ::= AS generated */ + -2, /* (374) conslist_opt ::= COMMA conslist */ + -3, /* (375) conslist ::= conslist tconscomma tcons */ + -1, /* (376) conslist ::= tcons */ + 0, /* (377) tconscomma ::= */ + -1, /* (378) defer_subclause_opt ::= defer_subclause */ + -1, /* (379) resolvetype ::= raisetype */ + -1, /* (380) selectnowith ::= oneselect */ + -1, /* (381) oneselect ::= values */ + -2, /* (382) sclp ::= selcollist COMMA */ + -1, /* (383) as ::= ID|STRING */ + -1, /* (384) indexed_opt ::= indexed_by */ + 0, /* (385) returning ::= */ + -1, /* (386) expr ::= term */ + -1, /* (387) likeop ::= LIKE_KW|MATCH */ + -1, /* (388) case_operand ::= expr */ + -1, /* (389) exprlist ::= nexprlist */ + -1, /* (390) nmnum ::= plus_num */ + -1, /* (391) nmnum ::= nm */ + -1, /* (392) nmnum ::= ON */ + -1, /* (393) nmnum ::= DELETE */ + -1, /* (394) nmnum ::= DEFAULT */ + -1, /* (395) plus_num ::= INTEGER|FLOAT */ + 0, /* (396) foreach_clause ::= */ + -3, /* (397) foreach_clause ::= FOR EACH ROW */ + 0, /* (398) tridxby ::= */ + -1, /* (399) database_kw_opt ::= DATABASE */ + 0, /* (400) database_kw_opt ::= */ + 0, /* (401) kwcolumn_opt ::= */ + -1, /* (402) kwcolumn_opt ::= COLUMNKW */ + -1, /* (403) vtabarglist ::= vtabarg */ + -3, /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ + -2, /* (405) vtabarg ::= vtabarg vtabargtoken */ + 0, /* (406) anylist ::= */ + -4, /* (407) anylist ::= anylist LP anylist RP */ + -2, /* (408) anylist ::= anylist ANY */ + 0, /* (409) with ::= */ + -1, /* (410) windowdefn_list ::= windowdefn */ + -1, /* (411) window ::= frame_opt */ }; static void yy_accept(yyParser*); /* Forward Declaration */ @@ -181210,16 +183369,16 @@ static YYACTIONTYPE yy_reduce( { sqlite3FinishCoding(pParse); } break; case 3: /* cmd ::= BEGIN transtype trans_opt */ -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy502);} +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy144);} break; case 4: /* transtype ::= */ -{yymsp[1].minor.yy502 = TK_DEFERRED;} +{yymsp[1].minor.yy144 = TK_DEFERRED;} break; case 5: /* transtype ::= DEFERRED */ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6); case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7); - case 324: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==324); -{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/} + case 328: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==328); +{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/} break; case 8: /* cmd ::= COMMIT|END trans_opt */ case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9); @@ -181242,7 +183401,7 @@ static YYACTIONTYPE yy_reduce( break; case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */ { - sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy502,0,0,yymsp[-2].minor.yy502); + sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy144,0,0,yymsp[-2].minor.yy144); } break; case 14: /* createkw ::= CREATE */ @@ -181258,38 +183417,38 @@ static YYACTIONTYPE yy_reduce( case 81: /* ifexists ::= */ yytestcase(yyruleno==81); case 100: /* distinct ::= */ yytestcase(yyruleno==100); case 246: /* collate ::= */ yytestcase(yyruleno==246); -{yymsp[1].minor.yy502 = 0;} +{yymsp[1].minor.yy144 = 0;} break; case 16: /* ifnotexists ::= IF NOT EXISTS */ -{yymsp[-2].minor.yy502 = 1;} +{yymsp[-2].minor.yy144 = 1;} break; case 17: /* temp ::= TEMP */ -{yymsp[0].minor.yy502 = pParse->db->init.busy==0;} +{yymsp[0].minor.yy144 = pParse->db->init.busy==0;} break; case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */ { - sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy9,0); + sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy391,0); } break; case 20: /* create_table_args ::= AS select */ { - sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy637); - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); + sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy555); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); } break; case 21: /* table_option_set ::= */ -{yymsp[1].minor.yy9 = 0;} +{yymsp[1].minor.yy391 = 0;} break; case 22: /* table_option_set ::= table_option_set COMMA table_option */ -{yylhsminor.yy9 = yymsp[-2].minor.yy9|yymsp[0].minor.yy9;} - yymsp[-2].minor.yy9 = yylhsminor.yy9; +{yylhsminor.yy391 = yymsp[-2].minor.yy391|yymsp[0].minor.yy391;} + yymsp[-2].minor.yy391 = yylhsminor.yy391; break; case 23: /* table_option ::= WITHOUT nm */ { if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){ - yymsp[-1].minor.yy9 = TF_WithoutRowid | TF_NoVisibleRowid; + yymsp[-1].minor.yy391 = TF_WithoutRowid | TF_NoVisibleRowid; }else{ - yymsp[-1].minor.yy9 = 0; + yymsp[-1].minor.yy391 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } @@ -181297,13 +183456,13 @@ static YYACTIONTYPE yy_reduce( case 24: /* table_option ::= nm */ { if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){ - yylhsminor.yy9 = TF_Strict; + yylhsminor.yy391 = TF_Strict; }else{ - yylhsminor.yy9 = 0; + yylhsminor.yy391 = 0; sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z); } } - yymsp[0].minor.yy9 = yylhsminor.yy9; + yymsp[0].minor.yy391 = yylhsminor.yy391; break; case 25: /* columnname ::= nm typetoken */ {sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);} @@ -181329,7 +183488,7 @@ static YYACTIONTYPE yy_reduce( case 30: /* scanpt ::= */ { assert( yyLookahead!=YYNOCODE ); - yymsp[1].minor.yy342 = yyLookaheadToken.z; + yymsp[1].minor.yy168 = yyLookaheadToken.z; } break; case 31: /* scantok ::= */ @@ -181343,17 +183502,17 @@ static YYACTIONTYPE yy_reduce( {ASSERT_IS_CREATE; pParse->u1.cr.constraintName = yymsp[0].minor.yy0;} break; case 33: /* ccons ::= DEFAULT scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 34: /* ccons ::= DEFAULT LP expr RP */ -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);} break; case 35: /* ccons ::= DEFAULT PLUS scantok term */ -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy590,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy454,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);} break; case 36: /* ccons ::= DEFAULT MINUS scantok term */ { - Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy590, 0); + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy454, 0); sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]); } break; @@ -181368,133 +183527,133 @@ static YYACTIONTYPE yy_reduce( } break; case 38: /* ccons ::= NOT NULL onconf */ -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy502);} +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy144);} break; case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */ -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy502,yymsp[0].minor.yy502,yymsp[-2].minor.yy502);} +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy144,yymsp[0].minor.yy144,yymsp[-2].minor.yy144);} break; case 40: /* ccons ::= UNIQUE onconf */ -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy502,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy144,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 41: /* ccons ::= CHECK LP expr RP */ -{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy590,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy454,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);} break; case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */ -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy402,yymsp[0].minor.yy502);} +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy14,yymsp[0].minor.yy144);} break; case 43: /* ccons ::= defer_subclause */ -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy502);} +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy144);} break; case 44: /* ccons ::= COLLATE ID|STRING */ {sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);} break; case 45: /* generated ::= LP expr RP */ -{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy590,0);} +{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy454,0);} break; case 46: /* generated ::= LP expr RP ID */ -{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy590,&yymsp[0].minor.yy0);} +{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy454,&yymsp[0].minor.yy0);} break; case 48: /* autoinc ::= AUTOINCR */ -{yymsp[0].minor.yy502 = 1;} +{yymsp[0].minor.yy144 = 1;} break; case 49: /* refargs ::= */ -{ yymsp[1].minor.yy502 = OE_None*0x0101; /* EV: R-19803-45884 */} +{ yymsp[1].minor.yy144 = OE_None*0x0101; /* EV: R-19803-45884 */} break; case 50: /* refargs ::= refargs refarg */ -{ yymsp[-1].minor.yy502 = (yymsp[-1].minor.yy502 & ~yymsp[0].minor.yy481.mask) | yymsp[0].minor.yy481.value; } +{ yymsp[-1].minor.yy144 = (yymsp[-1].minor.yy144 & ~yymsp[0].minor.yy383.mask) | yymsp[0].minor.yy383.value; } break; case 51: /* refarg ::= MATCH nm */ -{ yymsp[-1].minor.yy481.value = 0; yymsp[-1].minor.yy481.mask = 0x000000; } +{ yymsp[-1].minor.yy383.value = 0; yymsp[-1].minor.yy383.mask = 0x000000; } break; case 52: /* refarg ::= ON INSERT refact */ -{ yymsp[-2].minor.yy481.value = 0; yymsp[-2].minor.yy481.mask = 0x000000; } +{ yymsp[-2].minor.yy383.value = 0; yymsp[-2].minor.yy383.mask = 0x000000; } break; case 53: /* refarg ::= ON DELETE refact */ -{ yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502; yymsp[-2].minor.yy481.mask = 0x0000ff; } +{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144; yymsp[-2].minor.yy383.mask = 0x0000ff; } break; case 54: /* refarg ::= ON UPDATE refact */ -{ yymsp[-2].minor.yy481.value = yymsp[0].minor.yy502<<8; yymsp[-2].minor.yy481.mask = 0x00ff00; } +{ yymsp[-2].minor.yy383.value = yymsp[0].minor.yy144<<8; yymsp[-2].minor.yy383.mask = 0x00ff00; } break; case 55: /* refact ::= SET NULL */ -{ yymsp[-1].minor.yy502 = OE_SetNull; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy144 = OE_SetNull; /* EV: R-33326-45252 */} break; case 56: /* refact ::= SET DEFAULT */ -{ yymsp[-1].minor.yy502 = OE_SetDflt; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy144 = OE_SetDflt; /* EV: R-33326-45252 */} break; case 57: /* refact ::= CASCADE */ -{ yymsp[0].minor.yy502 = OE_Cascade; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy144 = OE_Cascade; /* EV: R-33326-45252 */} break; case 58: /* refact ::= RESTRICT */ -{ yymsp[0].minor.yy502 = OE_Restrict; /* EV: R-33326-45252 */} +{ yymsp[0].minor.yy144 = OE_Restrict; /* EV: R-33326-45252 */} break; case 59: /* refact ::= NO ACTION */ -{ yymsp[-1].minor.yy502 = OE_None; /* EV: R-33326-45252 */} +{ yymsp[-1].minor.yy144 = OE_None; /* EV: R-33326-45252 */} break; case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ -{yymsp[-2].minor.yy502 = 0;} +{yymsp[-2].minor.yy144 = 0;} break; case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */ case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76); case 173: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==173); -{yymsp[-1].minor.yy502 = yymsp[0].minor.yy502;} +{yymsp[-1].minor.yy144 = yymsp[0].minor.yy144;} break; case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80); case 219: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==219); case 222: /* in_op ::= NOT IN */ yytestcase(yyruleno==222); case 247: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==247); -{yymsp[-1].minor.yy502 = 1;} +{yymsp[-1].minor.yy144 = 1;} break; case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ -{yymsp[-1].minor.yy502 = 0;} +{yymsp[-1].minor.yy144 = 0;} break; case 66: /* tconscomma ::= COMMA */ {ASSERT_IS_CREATE; pParse->u1.cr.constraintName.n = 0;} break; case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */ -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy402,yymsp[0].minor.yy502,yymsp[-2].minor.yy502,0);} +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy14,yymsp[0].minor.yy144,yymsp[-2].minor.yy144,0);} break; case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */ -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy402,yymsp[0].minor.yy502,0,0,0,0, +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy14,yymsp[0].minor.yy144,0,0,0,0, SQLITE_IDXTYPE_UNIQUE);} break; case 70: /* tcons ::= CHECK LP expr RP onconf */ -{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy590,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy454,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);} break; case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */ { - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy402, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[-1].minor.yy502); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy502); + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy14, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[-1].minor.yy144); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy144); } break; case 73: /* onconf ::= */ case 75: /* orconf ::= */ yytestcase(yyruleno==75); -{yymsp[1].minor.yy502 = OE_Default;} +{yymsp[1].minor.yy144 = OE_Default;} break; case 74: /* onconf ::= ON CONFLICT resolvetype */ -{yymsp[-2].minor.yy502 = yymsp[0].minor.yy502;} +{yymsp[-2].minor.yy144 = yymsp[0].minor.yy144;} break; case 77: /* resolvetype ::= IGNORE */ -{yymsp[0].minor.yy502 = OE_Ignore;} +{yymsp[0].minor.yy144 = OE_Ignore;} break; case 78: /* resolvetype ::= REPLACE */ case 174: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==174); -{yymsp[0].minor.yy502 = OE_Replace;} +{yymsp[0].minor.yy144 = OE_Replace;} break; case 79: /* cmd ::= DROP TABLE ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy563, 0, yymsp[-1].minor.yy502); + sqlite3DropTable(pParse, yymsp[0].minor.yy203, 0, yymsp[-1].minor.yy144); } break; case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */ { - sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy402, yymsp[0].minor.yy637, yymsp[-7].minor.yy502, yymsp[-5].minor.yy502); + sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy14, yymsp[0].minor.yy555, yymsp[-7].minor.yy144, yymsp[-5].minor.yy144); } break; case 83: /* cmd ::= DROP VIEW ifexists fullname */ { - sqlite3DropTable(pParse, yymsp[0].minor.yy563, 1, yymsp[-1].minor.yy502); + sqlite3DropTable(pParse, yymsp[0].minor.yy203, 1, yymsp[-1].minor.yy144); } break; case 84: /* cmd ::= select */ @@ -181503,20 +183662,20 @@ static YYACTIONTYPE yy_reduce( if( (pParse->db->mDbFlags & DBFLAG_EncodingFixed)!=0 || sqlite3ReadSchema(pParse)==SQLITE_OK ){ - sqlite3Select(pParse, yymsp[0].minor.yy637, &dest); + sqlite3Select(pParse, yymsp[0].minor.yy555, &dest); } - sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy637); + sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy555); } break; case 85: /* select ::= WITH wqlist selectnowith */ -{yymsp[-2].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} +{yymsp[-2].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} break; case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */ -{yymsp[-3].minor.yy637 = attachWithToSelect(pParse,yymsp[0].minor.yy637,yymsp[-1].minor.yy125);} +{yymsp[-3].minor.yy555 = attachWithToSelect(pParse,yymsp[0].minor.yy555,yymsp[-1].minor.yy59);} break; case 87: /* select ::= selectnowith */ { - Select *p = yymsp[0].minor.yy637; + Select *p = yymsp[0].minor.yy555; if( p ){ parserDoubleLinkSelect(pParse, p); } @@ -181524,8 +183683,8 @@ static YYACTIONTYPE yy_reduce( break; case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */ { - Select *pRhs = yymsp[0].minor.yy637; - Select *pLhs = yymsp[-2].minor.yy637; + Select *pRhs = yymsp[0].minor.yy555; + Select *pLhs = yymsp[-2].minor.yy555; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; @@ -181535,60 +183694,60 @@ static YYACTIONTYPE yy_reduce( pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ - pRhs->op = (u8)yymsp[-1].minor.yy502; + pRhs->op = (u8)yymsp[-1].minor.yy144; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue; pRhs->selFlags &= ~(u32)SF_MultiValue; - if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1; + if( yymsp[-1].minor.yy144!=TK_ALL ) pParse->hasCompound = 1; }else{ sqlite3SelectDelete(pParse->db, pLhs); } - yymsp[-2].minor.yy637 = pRhs; + yymsp[-2].minor.yy555 = pRhs; } break; case 89: /* multiselect_op ::= UNION */ case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91); -{yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-OP*/} +{yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-OP*/} break; case 90: /* multiselect_op ::= UNION ALL */ -{yymsp[-1].minor.yy502 = TK_ALL;} +{yymsp[-1].minor.yy144 = TK_ALL;} break; case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */ { - yymsp[-8].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy402,yymsp[-5].minor.yy563,yymsp[-4].minor.yy590,yymsp[-3].minor.yy402,yymsp[-2].minor.yy590,yymsp[-1].minor.yy402,yymsp[-7].minor.yy502,yymsp[0].minor.yy590); + yymsp[-8].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy14,yymsp[-5].minor.yy203,yymsp[-4].minor.yy454,yymsp[-3].minor.yy14,yymsp[-2].minor.yy454,yymsp[-1].minor.yy14,yymsp[-7].minor.yy144,yymsp[0].minor.yy454); } break; case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */ { - yymsp[-9].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy402,yymsp[-6].minor.yy563,yymsp[-5].minor.yy590,yymsp[-4].minor.yy402,yymsp[-3].minor.yy590,yymsp[-1].minor.yy402,yymsp[-8].minor.yy502,yymsp[0].minor.yy590); - if( yymsp[-9].minor.yy637 ){ - yymsp[-9].minor.yy637->pWinDefn = yymsp[-2].minor.yy483; + yymsp[-9].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy14,yymsp[-6].minor.yy203,yymsp[-5].minor.yy454,yymsp[-4].minor.yy14,yymsp[-3].minor.yy454,yymsp[-1].minor.yy14,yymsp[-8].minor.yy144,yymsp[0].minor.yy454); + if( yymsp[-9].minor.yy555 ){ + yymsp[-9].minor.yy555->pWinDefn = yymsp[-2].minor.yy211; }else{ - sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy483); + sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy211); } } break; case 94: /* values ::= VALUES LP nexprlist RP */ { - yymsp[-3].minor.yy637 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy402,0,0,0,0,0,SF_Values,0); + yymsp[-3].minor.yy555 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy14,0,0,0,0,0,SF_Values,0); } break; case 95: /* oneselect ::= mvalues */ { - sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy637); + sqlite3MultiValuesEnd(pParse, yymsp[0].minor.yy555); } break; case 96: /* mvalues ::= values COMMA LP nexprlist RP */ case 97: /* mvalues ::= mvalues COMMA LP nexprlist RP */ yytestcase(yyruleno==97); { - yymsp[-4].minor.yy637 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy637, yymsp[-1].minor.yy402); + yymsp[-4].minor.yy555 = sqlite3MultiValues(pParse, yymsp[-4].minor.yy555, yymsp[-1].minor.yy14); } break; case 98: /* distinct ::= DISTINCT */ -{yymsp[0].minor.yy502 = SF_Distinct;} +{yymsp[0].minor.yy144 = SF_Distinct;} break; case 99: /* distinct ::= ALL */ -{yymsp[0].minor.yy502 = SF_All;} +{yymsp[0].minor.yy144 = SF_All;} break; case 101: /* sclp ::= */ case 134: /* orderby_opt ::= */ yytestcase(yyruleno==134); @@ -181596,20 +183755,20 @@ static YYACTIONTYPE yy_reduce( case 234: /* exprlist ::= */ yytestcase(yyruleno==234); case 237: /* paren_exprlist ::= */ yytestcase(yyruleno==237); case 242: /* eidlist_opt ::= */ yytestcase(yyruleno==242); -{yymsp[1].minor.yy402 = 0;} +{yymsp[1].minor.yy14 = 0;} break; case 102: /* selcollist ::= sclp scanpt expr scanpt as */ { - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); - if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[0].minor.yy0, 1); - sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy402,yymsp[-3].minor.yy342,yymsp[-1].minor.yy342); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); + if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[0].minor.yy0, 1); + sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy14,yymsp[-3].minor.yy168,yymsp[-1].minor.yy168); } break; case 103: /* selcollist ::= sclp scanpt STAR */ { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); - yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy402, p); + yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy14, p); } break; case 104: /* selcollist ::= sclp scanpt nm DOT STAR */ @@ -181619,7 +183778,7 @@ static YYACTIONTYPE yy_reduce( sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail)); pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0); pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, pDot); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, pDot); } break; case 105: /* as ::= AS nm */ @@ -181630,50 +183789,50 @@ static YYACTIONTYPE yy_reduce( break; case 107: /* from ::= */ case 110: /* stl_prefix ::= */ yytestcase(yyruleno==110); -{yymsp[1].minor.yy563 = 0;} +{yymsp[1].minor.yy203 = 0;} break; case 108: /* from ::= FROM seltablist */ { - yymsp[-1].minor.yy563 = yymsp[0].minor.yy563; - sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy563); + yymsp[-1].minor.yy203 = yymsp[0].minor.yy203; + sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy203); } break; case 109: /* stl_prefix ::= seltablist joinop */ { - if( ALWAYS(yymsp[-1].minor.yy563 && yymsp[-1].minor.yy563->nSrc>0) ) yymsp[-1].minor.yy563->a[yymsp[-1].minor.yy563->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy502; + if( ALWAYS(yymsp[-1].minor.yy203 && yymsp[-1].minor.yy203->nSrc>0) ) yymsp[-1].minor.yy203->a[yymsp[-1].minor.yy203->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy144; } break; case 111: /* seltablist ::= stl_prefix nm dbnm as on_using */ { - yymsp[-4].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy563,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); + yymsp[-4].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy203,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); } break; case 112: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */ { - yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy421); - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-1].minor.yy0); + yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy269); + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-1].minor.yy0); } break; case 113: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */ { - yymsp[-7].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy563,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); - sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy563, yymsp[-3].minor.yy402); + yymsp[-7].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy203,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); + sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy203, yymsp[-3].minor.yy14); } break; case 114: /* seltablist ::= stl_prefix LP select RP as on_using */ { - yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy637,&yymsp[0].minor.yy421); + yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy555,&yymsp[0].minor.yy269); } break; case 115: /* seltablist ::= stl_prefix LP seltablist RP as on_using */ { - if( yymsp[-5].minor.yy563==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy421.pOn==0 && yymsp[0].minor.yy421.pUsing==0 ){ - yymsp[-5].minor.yy563 = yymsp[-3].minor.yy563; - }else if( ALWAYS(yymsp[-3].minor.yy563!=0) && yymsp[-3].minor.yy563->nSrc==1 ){ - yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy421); - if( yymsp[-5].minor.yy563 ){ - SrcItem *pNew = &yymsp[-5].minor.yy563->a[yymsp[-5].minor.yy563->nSrc-1]; - SrcItem *pOld = yymsp[-3].minor.yy563->a; + if( yymsp[-5].minor.yy203==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy269.pOn==0 && yymsp[0].minor.yy269.pUsing==0 ){ + yymsp[-5].minor.yy203 = yymsp[-3].minor.yy203; + }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){ + yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); + if( yymsp[-5].minor.yy203 ){ + SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1]; + SrcItem *pOld = yymsp[-3].minor.yy203->a; assert( pOld->fg.fixedSchema==0 ); pNew->zName = pOld->zName; assert( pOld->fg.fixedSchema==0 ); @@ -181698,12 +183857,12 @@ static YYACTIONTYPE yy_reduce( } pOld->zName = 0; } - sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy563); + sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203); }else{ Select *pSubquery; - sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy563); - pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy563,0,0,0,0,SF_NestedFrom,0); - yymsp[-5].minor.yy563 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy563,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy421); + sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203); + pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy203,0,0,0,0,SF_NestedFrom,0); + yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy269); } } break; @@ -181712,57 +183871,67 @@ static YYACTIONTYPE yy_reduce( {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;} break; case 118: /* fullname ::= nm */ + case 120: /* xfullname ::= nm */ yytestcase(yyruleno==120); { - yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); - if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); + if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[0].minor.yy563 = yylhsminor.yy563; + yymsp[0].minor.yy203 = yylhsminor.yy203; break; case 119: /* fullname ::= nm DOT nm */ + case 121: /* xfullname ::= nm DOT nm */ yytestcase(yyruleno==121); { - yylhsminor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - if( IN_RENAME_OBJECT && yylhsminor.yy563 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy563->a[0].zName, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + if( IN_RENAME_OBJECT && yylhsminor.yy203 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[0].minor.yy0); } - yymsp[-2].minor.yy563 = yylhsminor.yy563; + yymsp[-2].minor.yy203 = yylhsminor.yy203; break; - case 120: /* xfullname ::= nm */ -{yymsp[0].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/} - break; - case 121: /* xfullname ::= nm DOT nm */ -{yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/} - break; - case 122: /* xfullname ::= nm DOT nm AS nm */ + case 122: /* xfullname ::= nm AS nm */ { - yymsp[-4].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/ - if( yymsp[-4].minor.yy563 ) yymsp[-4].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); + if( yylhsminor.yy203 ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[-2].minor.yy0); + }else{ + yylhsminor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + } + } } + yymsp[-2].minor.yy203 = yylhsminor.yy203; break; - case 123: /* xfullname ::= nm AS nm */ + case 123: /* xfullname ::= nm DOT nm AS nm */ { - yymsp[-2].minor.yy563 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/ - if( yymsp[-2].minor.yy563 ) yymsp[-2].minor.yy563->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + yylhsminor.yy203 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); + if( yylhsminor.yy203 ){ + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenMap(pParse, yylhsminor.yy203->a[0].zName, &yymsp[-2].minor.yy0); + }else{ + yylhsminor.yy203->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0); + } + } } + yymsp[-4].minor.yy203 = yylhsminor.yy203; break; case 124: /* joinop ::= COMMA|JOIN */ -{ yymsp[0].minor.yy502 = JT_INNER; } +{ yymsp[0].minor.yy144 = JT_INNER; } break; case 125: /* joinop ::= JOIN_KW JOIN */ -{yymsp[-1].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} +{yymsp[-1].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/} break; case 126: /* joinop ::= JOIN_KW nm JOIN */ -{yymsp[-2].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} +{yymsp[-2].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/} break; case 127: /* joinop ::= JOIN_KW nm nm JOIN */ -{yymsp[-3].minor.yy502 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} +{yymsp[-3].minor.yy144 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/} break; case 128: /* on_using ::= ON expr */ -{yymsp[-1].minor.yy421.pOn = yymsp[0].minor.yy590; yymsp[-1].minor.yy421.pUsing = 0;} +{yymsp[-1].minor.yy269.pOn = yymsp[0].minor.yy454; yymsp[-1].minor.yy269.pUsing = 0;} break; case 129: /* on_using ::= USING LP idlist RP */ -{yymsp[-3].minor.yy421.pOn = 0; yymsp[-3].minor.yy421.pUsing = yymsp[-1].minor.yy204;} +{yymsp[-3].minor.yy269.pOn = 0; yymsp[-3].minor.yy269.pUsing = yymsp[-1].minor.yy132;} break; case 130: /* on_using ::= */ -{yymsp[1].minor.yy421.pOn = 0; yymsp[1].minor.yy421.pUsing = 0;} +{yymsp[1].minor.yy269.pOn = 0; yymsp[1].minor.yy269.pUsing = 0;} break; case 132: /* indexed_by ::= INDEXED BY nm */ {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;} @@ -181772,35 +183941,35 @@ static YYACTIONTYPE yy_reduce( break; case 135: /* orderby_opt ::= ORDER BY sortlist */ case 145: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==145); -{yymsp[-2].minor.yy402 = yymsp[0].minor.yy402;} +{yymsp[-2].minor.yy14 = yymsp[0].minor.yy14;} break; case 136: /* sortlist ::= sortlist COMMA expr sortorder nulls */ { - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402,yymsp[-2].minor.yy590); - sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14,yymsp[-2].minor.yy454); + sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); } break; case 137: /* sortlist ::= expr sortorder nulls */ { - yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy590); /*A-overwrites-Y*/ - sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy402,yymsp[-1].minor.yy502,yymsp[0].minor.yy502); + yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy454); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy14,yymsp[-1].minor.yy144,yymsp[0].minor.yy144); } break; case 138: /* sortorder ::= ASC */ -{yymsp[0].minor.yy502 = SQLITE_SO_ASC;} +{yymsp[0].minor.yy144 = SQLITE_SO_ASC;} break; case 139: /* sortorder ::= DESC */ -{yymsp[0].minor.yy502 = SQLITE_SO_DESC;} +{yymsp[0].minor.yy144 = SQLITE_SO_DESC;} break; case 140: /* sortorder ::= */ case 143: /* nulls ::= */ yytestcase(yyruleno==143); -{yymsp[1].minor.yy502 = SQLITE_SO_UNDEFINED;} +{yymsp[1].minor.yy144 = SQLITE_SO_UNDEFINED;} break; case 141: /* nulls ::= NULLS FIRST */ -{yymsp[-1].minor.yy502 = SQLITE_SO_ASC;} +{yymsp[-1].minor.yy144 = SQLITE_SO_ASC;} break; case 142: /* nulls ::= NULLS LAST */ -{yymsp[-1].minor.yy502 = SQLITE_SO_DESC;} +{yymsp[-1].minor.yy144 = SQLITE_SO_DESC;} break; case 146: /* having_opt ::= */ case 148: /* limit_opt ::= */ yytestcase(yyruleno==148); @@ -181809,42 +183978,42 @@ static YYACTIONTYPE yy_reduce( case 232: /* case_else ::= */ yytestcase(yyruleno==232); case 233: /* case_operand ::= */ yytestcase(yyruleno==233); case 252: /* vinto ::= */ yytestcase(yyruleno==252); -{yymsp[1].minor.yy590 = 0;} +{yymsp[1].minor.yy454 = 0;} break; case 147: /* having_opt ::= HAVING expr */ case 154: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==154); case 156: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==156); case 231: /* case_else ::= ELSE expr */ yytestcase(yyruleno==231); case 251: /* vinto ::= INTO expr */ yytestcase(yyruleno==251); -{yymsp[-1].minor.yy590 = yymsp[0].minor.yy590;} +{yymsp[-1].minor.yy454 = yymsp[0].minor.yy454;} break; case 149: /* limit_opt ::= LIMIT expr */ -{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,0);} +{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,0);} break; case 150: /* limit_opt ::= LIMIT expr OFFSET expr */ -{yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} +{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} break; case 151: /* limit_opt ::= LIMIT expr COMMA expr */ -{yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy590,yymsp[-2].minor.yy590);} +{yymsp[-3].minor.yy454 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy454,yymsp[-2].minor.yy454);} break; case 152: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy563, &yymsp[-1].minor.yy0); - sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy563,yymsp[0].minor.yy590,0,0); + sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy203, &yymsp[-1].minor.yy0); + sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy203,yymsp[0].minor.yy454,0,0); } break; case 157: /* where_opt_ret ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-1].minor.yy590 = 0;} +{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-1].minor.yy454 = 0;} break; case 158: /* where_opt_ret ::= WHERE expr RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy402); yymsp[-3].minor.yy590 = yymsp[-2].minor.yy590;} +{sqlite3AddReturning(pParse,yymsp[0].minor.yy14); yymsp[-3].minor.yy454 = yymsp[-2].minor.yy454;} break; case 159: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */ { - sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy563, &yymsp[-4].minor.yy0); - sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy402,"set list"); - if( yymsp[-1].minor.yy563 ){ - SrcList *pFromClause = yymsp[-1].minor.yy563; + sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy203, &yymsp[-4].minor.yy0); + sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy14,"set list"); + if( yymsp[-1].minor.yy203 ){ + SrcList *pFromClause = yymsp[-1].minor.yy203; if( pFromClause->nSrc>1 ){ Select *pSubquery; Token as; @@ -181853,90 +184022,90 @@ static YYACTIONTYPE yy_reduce( as.z = 0; pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); } - yymsp[-5].minor.yy563 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy563, pFromClause); + yymsp[-5].minor.yy203 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy203, pFromClause); } - sqlite3Update(pParse,yymsp[-5].minor.yy563,yymsp[-2].minor.yy402,yymsp[0].minor.yy590,yymsp[-6].minor.yy502,0,0,0); + sqlite3Update(pParse,yymsp[-5].minor.yy203,yymsp[-2].minor.yy14,yymsp[0].minor.yy454,yymsp[-6].minor.yy144,0,0,0); } break; case 160: /* setlist ::= setlist COMMA nm EQ expr */ { - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy402, yymsp[0].minor.yy590); - sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, 1); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy14, yymsp[0].minor.yy454); + sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, 1); } break; case 161: /* setlist ::= setlist COMMA LP idlist RP EQ expr */ { - yymsp[-6].minor.yy402 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy402, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); + yymsp[-6].minor.yy14 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy14, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); } break; case 162: /* setlist ::= nm EQ expr */ { - yylhsminor.yy402 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy590); - sqlite3ExprListSetName(pParse, yylhsminor.yy402, &yymsp[-2].minor.yy0, 1); + yylhsminor.yy14 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy454); + sqlite3ExprListSetName(pParse, yylhsminor.yy14, &yymsp[-2].minor.yy0, 1); } - yymsp[-2].minor.yy402 = yylhsminor.yy402; + yymsp[-2].minor.yy14 = yylhsminor.yy14; break; case 163: /* setlist ::= LP idlist RP EQ expr */ { - yymsp[-4].minor.yy402 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy204, yymsp[0].minor.yy590); + yymsp[-4].minor.yy14 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy132, yymsp[0].minor.yy454); } break; case 164: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */ { - sqlite3Insert(pParse, yymsp[-3].minor.yy563, yymsp[-1].minor.yy637, yymsp[-2].minor.yy204, yymsp[-5].minor.yy502, yymsp[0].minor.yy403); + sqlite3Insert(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy555, yymsp[-2].minor.yy132, yymsp[-5].minor.yy144, yymsp[0].minor.yy122); } break; case 165: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */ { - sqlite3Insert(pParse, yymsp[-4].minor.yy563, 0, yymsp[-3].minor.yy204, yymsp[-6].minor.yy502, 0); + sqlite3Insert(pParse, yymsp[-4].minor.yy203, 0, yymsp[-3].minor.yy132, yymsp[-6].minor.yy144, 0); } break; case 166: /* upsert ::= */ -{ yymsp[1].minor.yy403 = 0; } +{ yymsp[1].minor.yy122 = 0; } break; case 167: /* upsert ::= RETURNING selcollist */ -{ yymsp[-1].minor.yy403 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy402); } +{ yymsp[-1].minor.yy122 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy14); } break; case 168: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */ -{ yymsp[-11].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy402,yymsp[-6].minor.yy590,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,yymsp[0].minor.yy403);} +{ yymsp[-11].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy14,yymsp[-6].minor.yy454,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,yymsp[0].minor.yy122);} break; case 169: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */ -{ yymsp[-8].minor.yy403 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy402,yymsp[-3].minor.yy590,0,0,yymsp[0].minor.yy403); } +{ yymsp[-8].minor.yy122 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy14,yymsp[-3].minor.yy454,0,0,yymsp[0].minor.yy122); } break; case 170: /* upsert ::= ON CONFLICT DO NOTHING returning */ -{ yymsp[-4].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } +{ yymsp[-4].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } break; case 171: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */ -{ yymsp[-7].minor.yy403 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590,0);} +{ yymsp[-7].minor.yy122 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454,0);} break; case 172: /* returning ::= RETURNING selcollist */ -{sqlite3AddReturning(pParse,yymsp[0].minor.yy402);} +{sqlite3AddReturning(pParse,yymsp[0].minor.yy14);} break; case 175: /* idlist_opt ::= */ -{yymsp[1].minor.yy204 = 0;} +{yymsp[1].minor.yy132 = 0;} break; case 176: /* idlist_opt ::= LP idlist RP */ -{yymsp[-2].minor.yy204 = yymsp[-1].minor.yy204;} +{yymsp[-2].minor.yy132 = yymsp[-1].minor.yy132;} break; case 177: /* idlist ::= idlist COMMA nm */ -{yymsp[-2].minor.yy204 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy204,&yymsp[0].minor.yy0);} +{yymsp[-2].minor.yy132 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy132,&yymsp[0].minor.yy0);} break; case 178: /* idlist ::= nm */ -{yymsp[0].minor.yy204 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} +{yymsp[0].minor.yy132 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/} break; case 179: /* expr ::= LP expr RP */ -{yymsp[-2].minor.yy590 = yymsp[-1].minor.yy590;} +{yymsp[-2].minor.yy454 = yymsp[-1].minor.yy454;} break; case 180: /* expr ::= ID|INDEXED|JOIN_KW */ -{yymsp[0].minor.yy590=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} +{yymsp[0].minor.yy454=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 181: /* expr ::= nm DOT nm */ { Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0); Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); - yylhsminor.yy590 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); + yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } - yymsp[-2].minor.yy590 = yylhsminor.yy590; + yymsp[-2].minor.yy454 = yylhsminor.yy454; break; case 182: /* expr ::= nm DOT nm DOT nm */ { @@ -181947,27 +184116,32 @@ static YYACTIONTYPE yy_reduce( if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, 0, temp1); } - yylhsminor.yy590 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); + yylhsminor.yy454 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } - yymsp[-4].minor.yy590 = yylhsminor.yy590; + yymsp[-4].minor.yy454 = yylhsminor.yy454; break; case 183: /* term ::= NULL|FLOAT|BLOB */ case 184: /* term ::= STRING */ yytestcase(yyruleno==184); -{yymsp[0].minor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} +{yymsp[0].minor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/} break; case 185: /* term ::= INTEGER */ { - yylhsminor.yy590 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1); - if( yylhsminor.yy590 ) yylhsminor.yy590->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); + int iValue; + if( sqlite3GetInt32(yymsp[0].minor.yy0.z, &iValue)==0 ){ + yylhsminor.yy454 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 0); + }else{ + yylhsminor.yy454 = sqlite3ExprInt32(pParse->db, iValue); + } + if( yylhsminor.yy454 ) yylhsminor.yy454->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail); } - yymsp[0].minor.yy590 = yylhsminor.yy590; + yymsp[0].minor.yy454 = yylhsminor.yy454; break; case 186: /* expr ::= VARIABLE */ { if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){ u32 n = yymsp[0].minor.yy0.n; - yymsp[0].minor.yy590 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); - sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy590, n); + yymsp[0].minor.yy454 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0); + sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy454, n); }else{ /* When doing a nested parse, one can include terms in an expression ** that look like this: #1 #2 ... These terms refer to registers @@ -181976,80 +184150,80 @@ static YYACTIONTYPE yy_reduce( assert( t.n>=2 ); if( pParse->nested==0 ){ parserSyntaxError(pParse, &t); - yymsp[0].minor.yy590 = 0; + yymsp[0].minor.yy454 = 0; }else{ - yymsp[0].minor.yy590 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); - if( yymsp[0].minor.yy590 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy590->iTable); + yymsp[0].minor.yy454 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( yymsp[0].minor.yy454 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy454->iTable); } } } break; case 187: /* expr ::= expr COLLATE ID|STRING */ { - yymsp[-2].minor.yy590 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy590, &yymsp[0].minor.yy0, 1); + yymsp[-2].minor.yy454 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy454, &yymsp[0].minor.yy0, 1); } break; case 188: /* expr ::= CAST LP expr AS typetoken RP */ { - yymsp[-5].minor.yy590 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); - sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy590, yymsp[-3].minor.yy590, 0); + yymsp[-5].minor.yy454 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1); + sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy454, yymsp[-3].minor.yy454, 0); } break; case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy502); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy144); } - yymsp[-4].minor.yy590 = yylhsminor.yy590; + yymsp[-4].minor.yy454 = yylhsminor.yy454; break; case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy402, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy502); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-1].minor.yy402); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy14, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy144); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-1].minor.yy14); } - yymsp[-7].minor.yy590 = yylhsminor.yy590; + yymsp[-7].minor.yy454 = yylhsminor.yy454; break; case 191: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0); } - yymsp[-3].minor.yy590 = yylhsminor.yy590; + yymsp[-3].minor.yy454 = yylhsminor.yy454; break; case 192: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy402, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy502); - sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy14, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy144); + sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); } - yymsp[-5].minor.yy590 = yylhsminor.yy590; + yymsp[-5].minor.yy454 = yylhsminor.yy454; break; case 193: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy402, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy502); - sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); - sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy590, yymsp[-2].minor.yy402); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy14, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy144); + sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); + sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy454, yymsp[-2].minor.yy14); } - yymsp[-8].minor.yy590 = yylhsminor.yy590; + yymsp[-8].minor.yy454 = yylhsminor.yy454; break; case 194: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); - sqlite3WindowAttach(pParse, yylhsminor.yy590, yymsp[0].minor.yy483); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0); + sqlite3WindowAttach(pParse, yylhsminor.yy454, yymsp[0].minor.yy211); } - yymsp[-4].minor.yy590 = yylhsminor.yy590; + yymsp[-4].minor.yy454 = yylhsminor.yy454; break; case 195: /* term ::= CTIME_KW */ { - yylhsminor.yy590 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0); } - yymsp[0].minor.yy590 = yylhsminor.yy590; + yymsp[0].minor.yy454 = yylhsminor.yy454; break; case 196: /* expr ::= LP nexprlist COMMA expr RP */ { - ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590); - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); - if( yymsp[-4].minor.yy590 ){ - yymsp[-4].minor.yy590->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( yymsp[-4].minor.yy454 ){ + yymsp[-4].minor.yy454->x.pList = pList; if( ALWAYS(pList->nExpr) ){ - yymsp[-4].minor.yy590->flags |= pList->a[0].pExpr->flags & EP_Propagate; + yymsp[-4].minor.yy454->flags |= pList->a[0].pExpr->flags & EP_Propagate; } }else{ sqlite3ExprListDelete(pParse->db, pList); @@ -182057,7 +184231,7 @@ static YYACTIONTYPE yy_reduce( } break; case 197: /* expr ::= expr AND expr */ -{yymsp[-2].minor.yy590=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} +{yymsp[-2].minor.yy454=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} break; case 198: /* expr ::= expr OR expr */ case 199: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==199); @@ -182066,7 +184240,7 @@ static YYACTIONTYPE yy_reduce( case 202: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==202); case 203: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==203); case 204: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==204); -{yymsp[-2].minor.yy590=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy590,yymsp[0].minor.yy590);} +{yymsp[-2].minor.yy454=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy454,yymsp[0].minor.yy454);} break; case 205: /* likeop ::= NOT LIKE_KW|MATCH */ {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/} @@ -182076,11 +184250,11 @@ static YYACTIONTYPE yy_reduce( ExprList *pList; int bNot = yymsp[-1].minor.yy0.n & 0x80000000; yymsp[-1].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy590); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy590); - yymsp[-2].minor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); - if( bNot ) yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy590, 0); - if( yymsp[-2].minor.yy590 ) yymsp[-2].minor.yy590->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy454); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy454); + yymsp[-2].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + if( bNot ) yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy454, 0); + if( yymsp[-2].minor.yy454 ) yymsp[-2].minor.yy454->flags |= EP_InfixFunc; } break; case 207: /* expr ::= expr likeop expr ESCAPE expr */ @@ -182088,91 +184262,87 @@ static YYACTIONTYPE yy_reduce( ExprList *pList; int bNot = yymsp[-3].minor.yy0.n & 0x80000000; yymsp[-3].minor.yy0.n &= 0x7fffffff; - pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy590); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590); - yymsp[-4].minor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); - if( bNot ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); - if( yymsp[-4].minor.yy590 ) yymsp[-4].minor.yy590->flags |= EP_InfixFunc; + pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy454); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); + yymsp[-4].minor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0); + if( bNot ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); + if( yymsp[-4].minor.yy454 ) yymsp[-4].minor.yy454->flags |= EP_InfixFunc; } break; case 208: /* expr ::= expr ISNULL|NOTNULL */ -{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy590,0);} +{yymsp[-1].minor.yy454 = sqlite3PExprIsNull(pParse,yymsp[0].major,yymsp[-1].minor.yy454);} break; case 209: /* expr ::= expr NOT NULL */ -{yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy590,0);} +{yymsp[-2].minor.yy454 = sqlite3PExprIsNull(pParse,TK_NOTNULL,yymsp[-2].minor.yy454);} break; case 210: /* expr ::= expr IS expr */ { - yymsp[-2].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy590,yymsp[0].minor.yy590); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-2].minor.yy590, TK_ISNULL); + yymsp[-2].minor.yy454 = sqlite3PExprIs(pParse, TK_IS, yymsp[-2].minor.yy454, yymsp[0].minor.yy454); } break; case 211: /* expr ::= expr IS NOT expr */ { - yymsp[-3].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy590,yymsp[0].minor.yy590); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-3].minor.yy590, TK_NOTNULL); + yymsp[-3].minor.yy454 = sqlite3PExprIs(pParse, TK_ISNOT, yymsp[-3].minor.yy454, yymsp[0].minor.yy454); } break; case 212: /* expr ::= expr IS NOT DISTINCT FROM expr */ { - yymsp[-5].minor.yy590 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy590,yymsp[0].minor.yy590); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-5].minor.yy590, TK_ISNULL); + yymsp[-5].minor.yy454 = sqlite3PExprIs(pParse, TK_IS, yymsp[-5].minor.yy454, yymsp[0].minor.yy454); } break; case 213: /* expr ::= expr IS DISTINCT FROM expr */ { - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy590,yymsp[0].minor.yy590); - binaryToUnaryIfNull(pParse, yymsp[0].minor.yy590, yymsp[-4].minor.yy590, TK_NOTNULL); + yymsp[-4].minor.yy454 = sqlite3PExprIs(pParse, TK_ISNOT, yymsp[-4].minor.yy454, yymsp[0].minor.yy454); } break; case 214: /* expr ::= NOT expr */ case 215: /* expr ::= BITNOT expr */ yytestcase(yyruleno==215); -{yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy590, 0);/*A-overwrites-B*/} +{yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy454, 0);/*A-overwrites-B*/} break; case 216: /* expr ::= PLUS|MINUS expr */ { - Expr *p = yymsp[0].minor.yy590; + Expr *p = yymsp[0].minor.yy454; u8 op = yymsp[-1].major + (TK_UPLUS-TK_PLUS); assert( TK_UPLUS>TK_PLUS ); assert( TK_UMINUS == TK_MINUS + (TK_UPLUS - TK_PLUS) ); if( p && p->op==TK_UPLUS ){ p->op = op; - yymsp[-1].minor.yy590 = p; + yymsp[-1].minor.yy454 = p; }else{ - yymsp[-1].minor.yy590 = sqlite3PExpr(pParse, op, p, 0); + yymsp[-1].minor.yy454 = sqlite3PExpr(pParse, op, p, 0); /*A-overwrites-B*/ } } break; case 217: /* expr ::= expr PTR expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy590); - pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy590); - yylhsminor.yy590 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); + ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy454); + pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy454); + yylhsminor.yy454 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0); } - yymsp[-2].minor.yy590 = yylhsminor.yy590; + yymsp[-2].minor.yy454 = yylhsminor.yy454; break; case 218: /* between_op ::= BETWEEN */ case 221: /* in_op ::= IN */ yytestcase(yyruleno==221); -{yymsp[0].minor.yy502 = 0;} +{yymsp[0].minor.yy144 = 0;} break; case 220: /* expr ::= expr between_op expr AND expr */ { - ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); - pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy590); - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy590, 0); - if( yymsp[-4].minor.yy590 ){ - yymsp[-4].minor.yy590->x.pList = pList; + ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); + pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy454); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy454, 0); + if( yymsp[-4].minor.yy454 ){ + yymsp[-4].minor.yy454->x.pList = pList; }else{ sqlite3ExprListDelete(pParse->db, pList); } - if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); + if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); } break; case 223: /* expr ::= expr in_op LP exprlist RP */ { - if( yymsp[-1].minor.yy402==0 ){ + if( yymsp[-1].minor.yy14==0 ){ /* Expressions of the form ** ** expr1 IN () @@ -182185,145 +184355,145 @@ static YYACTIONTYPE yy_reduce( ** it is or not) and if it is an aggregate, that could change the meaning ** of the whole query. */ - Expr *pB = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy502 ? "true" : "false"); + Expr *pB = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy144 ? "true" : "false"); if( pB ) sqlite3ExprIdToTrueFalse(pB); - if( !ExprHasProperty(yymsp[-4].minor.yy590, EP_HasFunc) ){ - sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy590); - yymsp[-4].minor.yy590 = pB; + if( !ExprHasProperty(yymsp[-4].minor.yy454, EP_HasFunc) ){ + sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy454); + yymsp[-4].minor.yy454 = pB; }else{ - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, yymsp[-3].minor.yy502 ? TK_OR : TK_AND, pB, yymsp[-4].minor.yy590); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, yymsp[-3].minor.yy144 ? TK_OR : TK_AND, pB, yymsp[-4].minor.yy454); } }else{ - Expr *pRHS = yymsp[-1].minor.yy402->a[0].pExpr; - if( yymsp[-1].minor.yy402->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy590->op!=TK_VECTOR ){ - yymsp[-1].minor.yy402->a[0].pExpr = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402); + Expr *pRHS = yymsp[-1].minor.yy14->a[0].pExpr; + if( yymsp[-1].minor.yy14->nExpr==1 && sqlite3ExprIsConstant(pParse,pRHS) && yymsp[-4].minor.yy454->op!=TK_VECTOR ){ + yymsp[-1].minor.yy14->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy590, pRHS); - }else if( yymsp[-1].minor.yy402->nExpr==1 && pRHS->op==TK_SELECT ){ - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pRHS->x.pSelect); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy454, pRHS); + }else if( yymsp[-1].minor.yy14->nExpr==1 && pRHS->op==TK_SELECT ){ + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pRHS->x.pSelect); pRHS->x.pSelect = 0; - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402); + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); }else{ - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); - if( yymsp[-4].minor.yy590==0 ){ - sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy402); - }else if( yymsp[-4].minor.yy590->pLeft->op==TK_VECTOR ){ - int nExpr = yymsp[-4].minor.yy590->pLeft->x.pList->nExpr; - Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy402); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); + if( yymsp[-4].minor.yy454==0 ){ + sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy14); + }else if( yymsp[-4].minor.yy454->pLeft->op==TK_VECTOR ){ + int nExpr = yymsp[-4].minor.yy454->pLeft->x.pList->nExpr; + Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy14); if( pSelectRHS ){ parserDoubleLinkSelect(pParse, pSelectRHS); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pSelectRHS); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelectRHS); } }else{ - yymsp[-4].minor.yy590->x.pList = yymsp[-1].minor.yy402; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy590); + yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy14; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); } } - if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); + if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); } } break; case 224: /* expr ::= LP select RP */ { - yymsp[-2].minor.yy590 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); - sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy590, yymsp[-1].minor.yy637); + yymsp[-2].minor.yy454 = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy454, yymsp[-1].minor.yy555); } break; case 225: /* expr ::= expr in_op LP select RP */ { - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, yymsp[-1].minor.yy637); - if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, yymsp[-1].minor.yy555); + if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); } break; case 226: /* expr ::= expr in_op nm dbnm paren_exprlist */ { SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); - if( yymsp[0].minor.yy402 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy402); - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy590, 0); - sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy590, pSelect); - if( yymsp[-3].minor.yy502 ) yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy590, 0); + if( yymsp[0].minor.yy14 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy14); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy454, 0); + sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy454, pSelect); + if( yymsp[-3].minor.yy144 ) yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy454, 0); } break; case 227: /* expr ::= EXISTS LP select RP */ { Expr *p; - p = yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); - sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy637); + p = yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy555); } break; case 228: /* expr ::= CASE case_operand case_exprlist case_else END */ { - yymsp[-4].minor.yy590 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy590, 0); - if( yymsp[-4].minor.yy590 ){ - yymsp[-4].minor.yy590->x.pList = yymsp[-1].minor.yy590 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[-1].minor.yy590) : yymsp[-2].minor.yy402; - sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy590); + yymsp[-4].minor.yy454 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy454, 0); + if( yymsp[-4].minor.yy454 ){ + yymsp[-4].minor.yy454->x.pList = yymsp[-1].minor.yy454 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[-1].minor.yy454) : yymsp[-2].minor.yy14; + sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy454); }else{ - sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy402); - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy590); + sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy14); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); } } break; case 229: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */ { - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[-2].minor.yy590); - yymsp[-4].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy402, yymsp[0].minor.yy590); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[-2].minor.yy454); + yymsp[-4].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy14, yymsp[0].minor.yy454); } break; case 230: /* case_exprlist ::= WHEN expr THEN expr */ { - yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy590); - yymsp[-3].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy402, yymsp[0].minor.yy590); + yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy454); + yymsp[-3].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy14, yymsp[0].minor.yy454); } break; case 235: /* nexprlist ::= nexprlist COMMA expr */ -{yymsp[-2].minor.yy402 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy402,yymsp[0].minor.yy590);} +{yymsp[-2].minor.yy14 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy14,yymsp[0].minor.yy454);} break; case 236: /* nexprlist ::= expr */ -{yymsp[0].minor.yy402 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy590); /*A-overwrites-Y*/} +{yymsp[0].minor.yy14 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy454); /*A-overwrites-Y*/} break; case 238: /* paren_exprlist ::= LP exprlist RP */ case 243: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==243); -{yymsp[-2].minor.yy402 = yymsp[-1].minor.yy402;} +{yymsp[-2].minor.yy14 = yymsp[-1].minor.yy14;} break; case 239: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */ { sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, - sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy402, yymsp[-10].minor.yy502, - &yymsp[-11].minor.yy0, yymsp[0].minor.yy590, SQLITE_SO_ASC, yymsp[-8].minor.yy502, SQLITE_IDXTYPE_APPDEF); + sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy14, yymsp[-10].minor.yy144, + &yymsp[-11].minor.yy0, yymsp[0].minor.yy454, SQLITE_SO_ASC, yymsp[-8].minor.yy144, SQLITE_IDXTYPE_APPDEF); if( IN_RENAME_OBJECT && pParse->pNewIndex ){ sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0); } } break; case 240: /* uniqueflag ::= UNIQUE */ - case 282: /* raisetype ::= ABORT */ yytestcase(yyruleno==282); -{yymsp[0].minor.yy502 = OE_Abort;} + case 281: /* raisetype ::= ABORT */ yytestcase(yyruleno==281); +{yymsp[0].minor.yy144 = OE_Abort;} break; case 241: /* uniqueflag ::= */ -{yymsp[1].minor.yy502 = OE_None;} +{yymsp[1].minor.yy144 = OE_None;} break; case 244: /* eidlist ::= eidlist COMMA nm collate sortorder */ { - yymsp[-4].minor.yy402 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy402, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); + yymsp[-4].minor.yy14 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy14, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); } break; case 245: /* eidlist ::= nm collate sortorder */ { - yymsp[-2].minor.yy402 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy502, yymsp[0].minor.yy502); /*A-overwrites-Y*/ + yymsp[-2].minor.yy14 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy144, yymsp[0].minor.yy144); /*A-overwrites-Y*/ } break; case 248: /* cmd ::= DROP INDEX ifexists fullname */ -{sqlite3DropIndex(pParse, yymsp[0].minor.yy563, yymsp[-1].minor.yy502);} +{sqlite3DropIndex(pParse, yymsp[0].minor.yy203, yymsp[-1].minor.yy144);} break; case 249: /* cmd ::= VACUUM vinto */ -{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy590);} +{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy454);} break; case 250: /* cmd ::= VACUUM nm vinto */ -{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy590);} +{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy454);} break; case 253: /* cmd ::= PRAGMA nm dbnm */ {sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);} @@ -182345,12 +184515,12 @@ static YYACTIONTYPE yy_reduce( Token all; all.z = yymsp[-3].minor.yy0.z; all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy319, &all); + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all); } break; case 261: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */ { - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy502, yymsp[-4].minor.yy28.a, yymsp[-4].minor.yy28.b, yymsp[-2].minor.yy563, yymsp[0].minor.yy590, yymsp[-10].minor.yy502, yymsp[-8].minor.yy502); + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy144, yymsp[-4].minor.yy286.a, yymsp[-4].minor.yy286.b, yymsp[-2].minor.yy203, yymsp[0].minor.yy454, yymsp[-10].minor.yy144, yymsp[-8].minor.yy144); yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/ #ifdef SQLITE_DEBUG assert( pParse->isCreate ); /* Set by createkw reduce action */ @@ -182359,421 +184529,439 @@ static YYACTIONTYPE yy_reduce( } break; case 262: /* trigger_time ::= BEFORE|AFTER */ -{ yymsp[0].minor.yy502 = yymsp[0].major; /*A-overwrites-X*/ } +{ yymsp[0].minor.yy144 = yymsp[0].major; /*A-overwrites-X*/ } break; case 263: /* trigger_time ::= INSTEAD OF */ -{ yymsp[-1].minor.yy502 = TK_INSTEAD;} +{ yymsp[-1].minor.yy144 = TK_INSTEAD;} break; case 264: /* trigger_time ::= */ -{ yymsp[1].minor.yy502 = TK_BEFORE; } +{ yymsp[1].minor.yy144 = TK_BEFORE; } break; case 265: /* trigger_event ::= DELETE|INSERT */ case 266: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==266); -{yymsp[0].minor.yy28.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy28.b = 0;} +{yymsp[0].minor.yy286.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy286.b = 0;} break; case 267: /* trigger_event ::= UPDATE OF idlist */ -{yymsp[-2].minor.yy28.a = TK_UPDATE; yymsp[-2].minor.yy28.b = yymsp[0].minor.yy204;} +{yymsp[-2].minor.yy286.a = TK_UPDATE; yymsp[-2].minor.yy286.b = yymsp[0].minor.yy132;} break; case 268: /* when_clause ::= */ - case 287: /* key_opt ::= */ yytestcase(yyruleno==287); -{ yymsp[1].minor.yy590 = 0; } + case 286: /* key_opt ::= */ yytestcase(yyruleno==286); +{ yymsp[1].minor.yy454 = 0; } break; case 269: /* when_clause ::= WHEN expr */ - case 288: /* key_opt ::= KEY expr */ yytestcase(yyruleno==288); -{ yymsp[-1].minor.yy590 = yymsp[0].minor.yy590; } + case 287: /* key_opt ::= KEY expr */ yytestcase(yyruleno==287); +{ yymsp[-1].minor.yy454 = yymsp[0].minor.yy454; } break; case 270: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */ { - assert( yymsp[-2].minor.yy319!=0 ); - yymsp[-2].minor.yy319->pLast->pNext = yymsp[-1].minor.yy319; - yymsp[-2].minor.yy319->pLast = yymsp[-1].minor.yy319; + yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427; + yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427; } break; case 271: /* trigger_cmd_list ::= trigger_cmd SEMI */ { - assert( yymsp[-1].minor.yy319!=0 ); - yymsp[-1].minor.yy319->pLast = yymsp[-1].minor.yy319; + yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427; } break; - case 272: /* trnm ::= nm DOT nm */ -{ - yymsp[-2].minor.yy0 = yymsp[0].minor.yy0; - sqlite3ErrorMsg(pParse, - "qualified table names are not allowed on INSERT, UPDATE, and DELETE " - "statements within triggers"); -} - break; - case 273: /* tridxby ::= INDEXED BY nm */ + case 272: /* tridxby ::= INDEXED BY nm */ { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 274: /* tridxby ::= NOT INDEXED */ + case 273: /* tridxby ::= NOT INDEXED */ { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } break; - case 275: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */ -{yylhsminor.yy319 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy563, yymsp[-3].minor.yy402, yymsp[-1].minor.yy590, yymsp[-7].minor.yy502, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy342);} - yymsp[-8].minor.yy319 = yylhsminor.yy319; + case 274: /* trigger_cmd ::= UPDATE orconf xfullname tridxby SET setlist from where_opt scanpt */ +{yylhsminor.yy427 = sqlite3TriggerUpdateStep(pParse, yymsp[-6].minor.yy203, yymsp[-2].minor.yy203, yymsp[-3].minor.yy14, yymsp[-1].minor.yy454, yymsp[-7].minor.yy144, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy168);} + yymsp[-8].minor.yy427 = yylhsminor.yy427; break; - case 276: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */ + case 275: /* trigger_cmd ::= scanpt insert_cmd INTO xfullname idlist_opt select upsert scanpt */ { - yylhsminor.yy319 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy204,yymsp[-2].minor.yy637,yymsp[-6].minor.yy502,yymsp[-1].minor.yy403,yymsp[-7].minor.yy342,yymsp[0].minor.yy342);/*yylhsminor.yy319-overwrites-yymsp[-6].minor.yy502*/ + yylhsminor.yy427 = sqlite3TriggerInsertStep(pParse,yymsp[-4].minor.yy203,yymsp[-3].minor.yy132,yymsp[-2].minor.yy555,yymsp[-6].minor.yy144,yymsp[-1].minor.yy122,yymsp[-7].minor.yy168,yymsp[0].minor.yy168);/*yylhsminor.yy427-overwrites-yymsp[-6].minor.yy144*/ } - yymsp[-7].minor.yy319 = yylhsminor.yy319; + yymsp[-7].minor.yy427 = yylhsminor.yy427; break; - case 277: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */ -{yylhsminor.yy319 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy590, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy342);} - yymsp[-5].minor.yy319 = yylhsminor.yy319; + case 276: /* trigger_cmd ::= DELETE FROM xfullname tridxby where_opt scanpt */ +{yylhsminor.yy427 = sqlite3TriggerDeleteStep(pParse, yymsp[-3].minor.yy203, yymsp[-1].minor.yy454, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy168);} + yymsp[-5].minor.yy427 = yylhsminor.yy427; break; - case 278: /* trigger_cmd ::= scanpt select scanpt */ -{yylhsminor.yy319 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy637, yymsp[-2].minor.yy342, yymsp[0].minor.yy342); /*yylhsminor.yy319-overwrites-yymsp[-1].minor.yy637*/} - yymsp[-2].minor.yy319 = yylhsminor.yy319; + case 277: /* trigger_cmd ::= scanpt select scanpt */ +{yylhsminor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy555, yymsp[-2].minor.yy168, yymsp[0].minor.yy168); /*yylhsminor.yy427-overwrites-yymsp[-1].minor.yy555*/} + yymsp[-2].minor.yy427 = yylhsminor.yy427; break; - case 279: /* expr ::= RAISE LP IGNORE RP */ + case 278: /* expr ::= RAISE LP IGNORE RP */ { - yymsp[-3].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); - if( yymsp[-3].minor.yy590 ){ - yymsp[-3].minor.yy590->affExpr = OE_Ignore; + yymsp[-3].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( yymsp[-3].minor.yy454 ){ + yymsp[-3].minor.yy454->affExpr = OE_Ignore; } } break; - case 280: /* expr ::= RAISE LP raisetype COMMA expr RP */ + case 279: /* expr ::= RAISE LP raisetype COMMA expr RP */ { - yymsp[-5].minor.yy590 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy590, 0); - if( yymsp[-5].minor.yy590 ) { - yymsp[-5].minor.yy590->affExpr = (char)yymsp[-3].minor.yy502; + yymsp[-5].minor.yy454 = sqlite3PExpr(pParse, TK_RAISE, yymsp[-1].minor.yy454, 0); + if( yymsp[-5].minor.yy454 ) { + yymsp[-5].minor.yy454->affExpr = (char)yymsp[-3].minor.yy144; } } break; - case 281: /* raisetype ::= ROLLBACK */ -{yymsp[0].minor.yy502 = OE_Rollback;} + case 280: /* raisetype ::= ROLLBACK */ +{yymsp[0].minor.yy144 = OE_Rollback;} break; - case 283: /* raisetype ::= FAIL */ -{yymsp[0].minor.yy502 = OE_Fail;} + case 282: /* raisetype ::= FAIL */ +{yymsp[0].minor.yy144 = OE_Fail;} break; - case 284: /* cmd ::= DROP TRIGGER ifexists fullname */ + case 283: /* cmd ::= DROP TRIGGER ifexists fullname */ { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy563,yymsp[-1].minor.yy502); + sqlite3DropTrigger(pParse,yymsp[0].minor.yy203,yymsp[-1].minor.yy144); } break; - case 285: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ + case 284: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */ { - sqlite3Attach(pParse, yymsp[-3].minor.yy590, yymsp[-1].minor.yy590, yymsp[0].minor.yy590); + sqlite3Attach(pParse, yymsp[-3].minor.yy454, yymsp[-1].minor.yy454, yymsp[0].minor.yy454); } break; - case 286: /* cmd ::= DETACH database_kw_opt expr */ + case 285: /* cmd ::= DETACH database_kw_opt expr */ { - sqlite3Detach(pParse, yymsp[0].minor.yy590); + sqlite3Detach(pParse, yymsp[0].minor.yy454); } break; - case 289: /* cmd ::= REINDEX */ + case 288: /* cmd ::= REINDEX */ {sqlite3Reindex(pParse, 0, 0);} break; - case 290: /* cmd ::= REINDEX nm dbnm */ + case 289: /* cmd ::= REINDEX nm dbnm */ {sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 291: /* cmd ::= ANALYZE */ + case 290: /* cmd ::= ANALYZE */ {sqlite3Analyze(pParse, 0, 0);} break; - case 292: /* cmd ::= ANALYZE nm dbnm */ + case 291: /* cmd ::= ANALYZE nm dbnm */ {sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);} break; - case 293: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ + case 292: /* cmd ::= ALTER TABLE fullname RENAME TO nm */ { - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy563,&yymsp[0].minor.yy0); + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy203,&yymsp[0].minor.yy0); } break; - case 294: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */ + case 293: /* cmd ::= alter_add carglist */ { yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n; sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0); } break; - case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ -{ - sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy563, &yymsp[0].minor.yy0); -} - break; - case 296: /* add_column_fullname ::= fullname */ + case 294: /* alter_add ::= ALTER TABLE fullname ADD kwcolumn_opt nm typetoken */ { disableLookaside(pParse); - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy563); + sqlite3AlterBeginAddColumn(pParse, yymsp[-4].minor.yy203); + sqlite3AddColumn(pParse, yymsp[-1].minor.yy0, yymsp[0].minor.yy0); + yymsp[-6].minor.yy0 = yymsp[-1].minor.yy0; } break; - case 297: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ + case 295: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */ { - sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy563, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); + sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0); } break; - case 298: /* cmd ::= create_vtab */ + case 296: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */ +{ + sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy203, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0); +} + break; + case 297: /* cmd ::= ALTER TABLE fullname DROP CONSTRAINT nm */ +{ + sqlite3AlterDropConstraint(pParse, yymsp[-3].minor.yy203, &yymsp[0].minor.yy0, 0); +} + break; + case 298: /* cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm DROP NOT NULL */ +{ + sqlite3AlterDropConstraint(pParse, yymsp[-6].minor.yy203, 0, &yymsp[-3].minor.yy0); +} + break; + case 299: /* cmd ::= ALTER TABLE fullname ALTER kwcolumn_opt nm SET NOT NULL onconf */ +{ + sqlite3AlterSetNotNull(pParse, yymsp[-7].minor.yy203, &yymsp[-4].minor.yy0, &yymsp[-2].minor.yy0); +} + break; + case 300: /* cmd ::= ALTER TABLE fullname ADD CONSTRAINT nm CHECK LP expr RP onconf */ +{ + sqlite3AlterAddConstraint(pParse, yymsp[-8].minor.yy203, &yymsp[-6].minor.yy0, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1)); +} + yy_destructor(yypParser,219,&yymsp[-2].minor); + break; + case 301: /* cmd ::= ALTER TABLE fullname ADD CHECK LP expr RP onconf */ +{ + sqlite3AlterAddConstraint(pParse, yymsp[-6].minor.yy203, &yymsp[-4].minor.yy0, 0, yymsp[-3].minor.yy0.z+1, (yymsp[-1].minor.yy0.z-yymsp[-3].minor.yy0.z-1)); +} + yy_destructor(yypParser,219,&yymsp[-2].minor); + break; + case 302: /* cmd ::= create_vtab */ {sqlite3VtabFinishParse(pParse,0);} break; - case 299: /* cmd ::= create_vtab LP vtabarglist RP */ + case 303: /* cmd ::= create_vtab LP vtabarglist RP */ {sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);} break; - case 300: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ + case 304: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */ { - sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy502); + sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy144); } break; - case 301: /* vtabarg ::= */ + case 305: /* vtabarg ::= */ {sqlite3VtabArgInit(pParse);} break; - case 302: /* vtabargtoken ::= ANY */ - case 303: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==303); - case 304: /* lp ::= LP */ yytestcase(yyruleno==304); + case 306: /* vtabargtoken ::= ANY */ + case 307: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==307); + case 308: /* lp ::= LP */ yytestcase(yyruleno==308); {sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);} break; - case 305: /* with ::= WITH wqlist */ - case 306: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==306); -{ sqlite3WithPush(pParse, yymsp[0].minor.yy125, 1); } + case 309: /* with ::= WITH wqlist */ + case 310: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==310); +{ sqlite3WithPush(pParse, yymsp[0].minor.yy59, 1); } break; - case 307: /* wqas ::= AS */ -{yymsp[0].minor.yy444 = M10d_Any;} + case 311: /* wqas ::= AS */ +{yymsp[0].minor.yy462 = M10d_Any;} break; - case 308: /* wqas ::= AS MATERIALIZED */ -{yymsp[-1].minor.yy444 = M10d_Yes;} + case 312: /* wqas ::= AS MATERIALIZED */ +{yymsp[-1].minor.yy462 = M10d_Yes;} break; - case 309: /* wqas ::= AS NOT MATERIALIZED */ -{yymsp[-2].minor.yy444 = M10d_No;} + case 313: /* wqas ::= AS NOT MATERIALIZED */ +{yymsp[-2].minor.yy462 = M10d_No;} break; - case 310: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ + case 314: /* wqitem ::= withnm eidlist_opt wqas LP select RP */ { - yymsp[-5].minor.yy361 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy402, yymsp[-1].minor.yy637, yymsp[-3].minor.yy444); /*A-overwrites-X*/ + yymsp[-5].minor.yy67 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy14, yymsp[-1].minor.yy555, yymsp[-3].minor.yy462); /*A-overwrites-X*/ } break; - case 311: /* withnm ::= nm */ + case 315: /* withnm ::= nm */ {pParse->bHasWith = 1;} break; - case 312: /* wqlist ::= wqitem */ + case 316: /* wqlist ::= wqitem */ { - yymsp[0].minor.yy125 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy361); /*A-overwrites-X*/ + yymsp[0].minor.yy59 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy67); /*A-overwrites-X*/ } break; - case 313: /* wqlist ::= wqlist COMMA wqitem */ + case 317: /* wqlist ::= wqlist COMMA wqitem */ { - yymsp[-2].minor.yy125 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy125, yymsp[0].minor.yy361); + yymsp[-2].minor.yy59 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy59, yymsp[0].minor.yy67); } break; - case 314: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ + case 318: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */ { - assert( yymsp[0].minor.yy483!=0 ); - sqlite3WindowChain(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy483); - yymsp[0].minor.yy483->pNextWin = yymsp[-2].minor.yy483; - yylhsminor.yy483 = yymsp[0].minor.yy483; + assert( yymsp[0].minor.yy211!=0 ); + sqlite3WindowChain(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy211); + yymsp[0].minor.yy211->pNextWin = yymsp[-2].minor.yy211; + yylhsminor.yy211 = yymsp[0].minor.yy211; } - yymsp[-2].minor.yy483 = yylhsminor.yy483; + yymsp[-2].minor.yy211 = yylhsminor.yy211; break; - case 315: /* windowdefn ::= nm AS LP window RP */ + case 319: /* windowdefn ::= nm AS LP window RP */ { - if( ALWAYS(yymsp[-1].minor.yy483) ){ - yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); + if( ALWAYS(yymsp[-1].minor.yy211) ){ + yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n); } - yylhsminor.yy483 = yymsp[-1].minor.yy483; + yylhsminor.yy211 = yymsp[-1].minor.yy211; } - yymsp[-4].minor.yy483 = yylhsminor.yy483; + yymsp[-4].minor.yy211 = yylhsminor.yy211; break; - case 316: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ + case 320: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */ { - yymsp[-4].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, 0); + yymsp[-4].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, 0); } break; - case 317: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ + case 321: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */ { - yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, yymsp[-2].minor.yy402, yymsp[-1].minor.yy402, &yymsp[-5].minor.yy0); + yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, yymsp[-2].minor.yy14, yymsp[-1].minor.yy14, &yymsp[-5].minor.yy0); } - yymsp[-5].minor.yy483 = yylhsminor.yy483; + yymsp[-5].minor.yy211 = yylhsminor.yy211; break; - case 318: /* window ::= ORDER BY sortlist frame_opt */ + case 322: /* window ::= ORDER BY sortlist frame_opt */ { - yymsp[-3].minor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, 0); + yymsp[-3].minor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, 0); } break; - case 319: /* window ::= nm ORDER BY sortlist frame_opt */ + case 323: /* window ::= nm ORDER BY sortlist frame_opt */ { - yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, yymsp[-1].minor.yy402, &yymsp[-4].minor.yy0); + yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, yymsp[-1].minor.yy14, &yymsp[-4].minor.yy0); } - yymsp[-4].minor.yy483 = yylhsminor.yy483; + yymsp[-4].minor.yy211 = yylhsminor.yy211; break; - case 320: /* window ::= nm frame_opt */ + case 324: /* window ::= nm frame_opt */ { - yylhsminor.yy483 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy483, 0, 0, &yymsp[-1].minor.yy0); + yylhsminor.yy211 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy211, 0, 0, &yymsp[-1].minor.yy0); } - yymsp[-1].minor.yy483 = yylhsminor.yy483; + yymsp[-1].minor.yy211 = yylhsminor.yy211; break; - case 321: /* frame_opt ::= */ + case 325: /* frame_opt ::= */ { - yymsp[1].minor.yy483 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); + yymsp[1].minor.yy211 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); } break; - case 322: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ + case 326: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */ { - yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy502, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy444); + yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy144, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy462); } - yymsp[-2].minor.yy483 = yylhsminor.yy483; + yymsp[-2].minor.yy211 = yylhsminor.yy211; break; - case 323: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ + case 327: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */ { - yylhsminor.yy483 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy502, yymsp[-3].minor.yy205.eType, yymsp[-3].minor.yy205.pExpr, yymsp[-1].minor.yy205.eType, yymsp[-1].minor.yy205.pExpr, yymsp[0].minor.yy444); + yylhsminor.yy211 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy144, yymsp[-3].minor.yy509.eType, yymsp[-3].minor.yy509.pExpr, yymsp[-1].minor.yy509.eType, yymsp[-1].minor.yy509.pExpr, yymsp[0].minor.yy462); } - yymsp[-5].minor.yy483 = yylhsminor.yy483; + yymsp[-5].minor.yy211 = yylhsminor.yy211; break; - case 325: /* frame_bound_s ::= frame_bound */ - case 327: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==327); -{yylhsminor.yy205 = yymsp[0].minor.yy205;} - yymsp[0].minor.yy205 = yylhsminor.yy205; + case 329: /* frame_bound_s ::= frame_bound */ + case 331: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==331); +{yylhsminor.yy509 = yymsp[0].minor.yy509;} + yymsp[0].minor.yy509 = yylhsminor.yy509; break; - case 326: /* frame_bound_s ::= UNBOUNDED PRECEDING */ - case 328: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==328); - case 330: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==330); -{yylhsminor.yy205.eType = yymsp[-1].major; yylhsminor.yy205.pExpr = 0;} - yymsp[-1].minor.yy205 = yylhsminor.yy205; + case 330: /* frame_bound_s ::= UNBOUNDED PRECEDING */ + case 332: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==332); + case 334: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==334); +{yylhsminor.yy509.eType = yymsp[-1].major; yylhsminor.yy509.pExpr = 0;} + yymsp[-1].minor.yy509 = yylhsminor.yy509; break; - case 329: /* frame_bound ::= expr PRECEDING|FOLLOWING */ -{yylhsminor.yy205.eType = yymsp[0].major; yylhsminor.yy205.pExpr = yymsp[-1].minor.yy590;} - yymsp[-1].minor.yy205 = yylhsminor.yy205; + case 333: /* frame_bound ::= expr PRECEDING|FOLLOWING */ +{yylhsminor.yy509.eType = yymsp[0].major; yylhsminor.yy509.pExpr = yymsp[-1].minor.yy454;} + yymsp[-1].minor.yy509 = yylhsminor.yy509; break; - case 331: /* frame_exclude_opt ::= */ -{yymsp[1].minor.yy444 = 0;} + case 335: /* frame_exclude_opt ::= */ +{yymsp[1].minor.yy462 = 0;} break; - case 332: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ -{yymsp[-1].minor.yy444 = yymsp[0].minor.yy444;} + case 336: /* frame_exclude_opt ::= EXCLUDE frame_exclude */ +{yymsp[-1].minor.yy462 = yymsp[0].minor.yy462;} break; - case 333: /* frame_exclude ::= NO OTHERS */ - case 334: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==334); -{yymsp[-1].minor.yy444 = yymsp[-1].major; /*A-overwrites-X*/} + case 337: /* frame_exclude ::= NO OTHERS */ + case 338: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==338); +{yymsp[-1].minor.yy462 = yymsp[-1].major; /*A-overwrites-X*/} break; - case 335: /* frame_exclude ::= GROUP|TIES */ -{yymsp[0].minor.yy444 = yymsp[0].major; /*A-overwrites-X*/} + case 339: /* frame_exclude ::= GROUP|TIES */ +{yymsp[0].minor.yy462 = yymsp[0].major; /*A-overwrites-X*/} break; - case 336: /* window_clause ::= WINDOW windowdefn_list */ -{ yymsp[-1].minor.yy483 = yymsp[0].minor.yy483; } + case 340: /* window_clause ::= WINDOW windowdefn_list */ +{ yymsp[-1].minor.yy211 = yymsp[0].minor.yy211; } break; - case 337: /* filter_over ::= filter_clause over_clause */ + case 341: /* filter_over ::= filter_clause over_clause */ { - if( yymsp[0].minor.yy483 ){ - yymsp[0].minor.yy483->pFilter = yymsp[-1].minor.yy590; + if( yymsp[0].minor.yy211 ){ + yymsp[0].minor.yy211->pFilter = yymsp[-1].minor.yy454; }else{ - sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy590); + sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy454); } - yylhsminor.yy483 = yymsp[0].minor.yy483; + yylhsminor.yy211 = yymsp[0].minor.yy211; } - yymsp[-1].minor.yy483 = yylhsminor.yy483; + yymsp[-1].minor.yy211 = yylhsminor.yy211; break; - case 338: /* filter_over ::= over_clause */ + case 342: /* filter_over ::= over_clause */ { - yylhsminor.yy483 = yymsp[0].minor.yy483; + yylhsminor.yy211 = yymsp[0].minor.yy211; } - yymsp[0].minor.yy483 = yylhsminor.yy483; + yymsp[0].minor.yy211 = yylhsminor.yy211; break; - case 339: /* filter_over ::= filter_clause */ + case 343: /* filter_over ::= filter_clause */ { - yylhsminor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yylhsminor.yy483 ){ - yylhsminor.yy483->eFrmType = TK_FILTER; - yylhsminor.yy483->pFilter = yymsp[0].minor.yy590; + yylhsminor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yylhsminor.yy211 ){ + yylhsminor.yy211->eFrmType = TK_FILTER; + yylhsminor.yy211->pFilter = yymsp[0].minor.yy454; }else{ - sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy590); + sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy454); } } - yymsp[0].minor.yy483 = yylhsminor.yy483; + yymsp[0].minor.yy211 = yylhsminor.yy211; break; - case 340: /* over_clause ::= OVER LP window RP */ + case 344: /* over_clause ::= OVER LP window RP */ { - yymsp[-3].minor.yy483 = yymsp[-1].minor.yy483; - assert( yymsp[-3].minor.yy483!=0 ); + yymsp[-3].minor.yy211 = yymsp[-1].minor.yy211; + assert( yymsp[-3].minor.yy211!=0 ); } break; - case 341: /* over_clause ::= OVER nm */ + case 345: /* over_clause ::= OVER nm */ { - yymsp[-1].minor.yy483 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); - if( yymsp[-1].minor.yy483 ){ - yymsp[-1].minor.yy483->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); + yymsp[-1].minor.yy211 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( yymsp[-1].minor.yy211 ){ + yymsp[-1].minor.yy211->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n); } } break; - case 342: /* filter_clause ::= FILTER LP WHERE expr RP */ -{ yymsp[-4].minor.yy590 = yymsp[-1].minor.yy590; } + case 346: /* filter_clause ::= FILTER LP WHERE expr RP */ +{ yymsp[-4].minor.yy454 = yymsp[-1].minor.yy454; } break; - case 343: /* term ::= QNUMBER */ + case 347: /* term ::= QNUMBER */ { - yylhsminor.yy590=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); - sqlite3DequoteNumber(pParse, yylhsminor.yy590); + yylhsminor.yy454=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); + sqlite3DequoteNumber(pParse, yylhsminor.yy454); } - yymsp[0].minor.yy590 = yylhsminor.yy590; + yymsp[0].minor.yy454 = yylhsminor.yy454; break; default: - /* (344) input ::= cmdlist */ yytestcase(yyruleno==344); - /* (345) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==345); - /* (346) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=346); - /* (347) ecmd ::= SEMI */ yytestcase(yyruleno==347); - /* (348) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==348); - /* (349) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=349); - /* (350) trans_opt ::= */ yytestcase(yyruleno==350); - /* (351) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==351); - /* (352) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==352); - /* (353) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==353); - /* (354) savepoint_opt ::= */ yytestcase(yyruleno==354); - /* (355) cmd ::= create_table create_table_args */ yytestcase(yyruleno==355); - /* (356) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=356); - /* (357) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==357); - /* (358) columnlist ::= columnname carglist */ yytestcase(yyruleno==358); - /* (359) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==359); - /* (360) nm ::= STRING */ yytestcase(yyruleno==360); - /* (361) typetoken ::= typename */ yytestcase(yyruleno==361); - /* (362) typename ::= ID|STRING */ yytestcase(yyruleno==362); - /* (363) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=363); - /* (364) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=364); - /* (365) carglist ::= carglist ccons */ yytestcase(yyruleno==365); - /* (366) carglist ::= */ yytestcase(yyruleno==366); - /* (367) ccons ::= NULL onconf */ yytestcase(yyruleno==367); - /* (368) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==368); - /* (369) ccons ::= AS generated */ yytestcase(yyruleno==369); - /* (370) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==370); - /* (371) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==371); - /* (372) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=372); - /* (373) tconscomma ::= */ yytestcase(yyruleno==373); - /* (374) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=374); - /* (375) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=375); - /* (376) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=376); - /* (377) oneselect ::= values */ yytestcase(yyruleno==377); - /* (378) sclp ::= selcollist COMMA */ yytestcase(yyruleno==378); - /* (379) as ::= ID|STRING */ yytestcase(yyruleno==379); - /* (380) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=380); - /* (381) returning ::= */ yytestcase(yyruleno==381); - /* (382) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=382); - /* (383) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==383); - /* (384) case_operand ::= expr */ yytestcase(yyruleno==384); - /* (385) exprlist ::= nexprlist */ yytestcase(yyruleno==385); - /* (386) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=386); - /* (387) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=387); - /* (388) nmnum ::= ON */ yytestcase(yyruleno==388); - /* (389) nmnum ::= DELETE */ yytestcase(yyruleno==389); - /* (390) nmnum ::= DEFAULT */ yytestcase(yyruleno==390); - /* (391) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==391); - /* (392) foreach_clause ::= */ yytestcase(yyruleno==392); - /* (393) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==393); - /* (394) trnm ::= nm */ yytestcase(yyruleno==394); - /* (395) tridxby ::= */ yytestcase(yyruleno==395); - /* (396) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==396); - /* (397) database_kw_opt ::= */ yytestcase(yyruleno==397); - /* (398) kwcolumn_opt ::= */ yytestcase(yyruleno==398); - /* (399) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==399); - /* (400) vtabarglist ::= vtabarg */ yytestcase(yyruleno==400); - /* (401) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==401); - /* (402) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==402); - /* (403) anylist ::= */ yytestcase(yyruleno==403); - /* (404) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==404); - /* (405) anylist ::= anylist ANY */ yytestcase(yyruleno==405); - /* (406) with ::= */ yytestcase(yyruleno==406); - /* (407) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=407); - /* (408) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=408); + /* (348) input ::= cmdlist */ yytestcase(yyruleno==348); + /* (349) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==349); + /* (350) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=350); + /* (351) ecmd ::= SEMI */ yytestcase(yyruleno==351); + /* (352) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==352); + /* (353) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=353); + /* (354) trans_opt ::= */ yytestcase(yyruleno==354); + /* (355) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==355); + /* (356) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==356); + /* (357) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==357); + /* (358) savepoint_opt ::= */ yytestcase(yyruleno==358); + /* (359) cmd ::= create_table create_table_args */ yytestcase(yyruleno==359); + /* (360) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=360); + /* (361) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==361); + /* (362) columnlist ::= columnname carglist */ yytestcase(yyruleno==362); + /* (363) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==363); + /* (364) nm ::= STRING */ yytestcase(yyruleno==364); + /* (365) typetoken ::= typename */ yytestcase(yyruleno==365); + /* (366) typename ::= ID|STRING */ yytestcase(yyruleno==366); + /* (367) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=367); + /* (368) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=368); + /* (369) carglist ::= carglist ccons */ yytestcase(yyruleno==369); + /* (370) carglist ::= */ yytestcase(yyruleno==370); + /* (371) ccons ::= NULL onconf */ yytestcase(yyruleno==371); + /* (372) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==372); + /* (373) ccons ::= AS generated */ yytestcase(yyruleno==373); + /* (374) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==374); + /* (375) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==375); + /* (376) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=376); + /* (377) tconscomma ::= */ yytestcase(yyruleno==377); + /* (378) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=378); + /* (379) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=379); + /* (380) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=380); + /* (381) oneselect ::= values */ yytestcase(yyruleno==381); + /* (382) sclp ::= selcollist COMMA */ yytestcase(yyruleno==382); + /* (383) as ::= ID|STRING */ yytestcase(yyruleno==383); + /* (384) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=384); + /* (385) returning ::= */ yytestcase(yyruleno==385); + /* (386) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=386); + /* (387) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==387); + /* (388) case_operand ::= expr */ yytestcase(yyruleno==388); + /* (389) exprlist ::= nexprlist */ yytestcase(yyruleno==389); + /* (390) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=390); + /* (391) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=391); + /* (392) nmnum ::= ON */ yytestcase(yyruleno==392); + /* (393) nmnum ::= DELETE */ yytestcase(yyruleno==393); + /* (394) nmnum ::= DEFAULT */ yytestcase(yyruleno==394); + /* (395) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==395); + /* (396) foreach_clause ::= */ yytestcase(yyruleno==396); + /* (397) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==397); + /* (398) tridxby ::= */ yytestcase(yyruleno==398); + /* (399) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==399); + /* (400) database_kw_opt ::= */ yytestcase(yyruleno==400); + /* (401) kwcolumn_opt ::= */ yytestcase(yyruleno==401); + /* (402) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==402); + /* (403) vtabarglist ::= vtabarg */ yytestcase(yyruleno==403); + /* (404) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==404); + /* (405) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==405); + /* (406) anylist ::= */ yytestcase(yyruleno==406); + /* (407) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==407); + /* (408) anylist ::= anylist ANY */ yytestcase(yyruleno==408); + /* (409) with ::= */ yytestcase(yyruleno==409); + /* (410) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=410); + /* (411) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=411); break; /********** End reduce actions ************************************************/ }; @@ -183552,8 +185740,8 @@ static const unsigned char aKWCode[148] = {0, /* Check to see if z[0..n-1] is a keyword. If it is, write the ** parser symbol code for that keyword into *pType. Always ** return the integer n (the length of the token). */ -static int keywordCode(const char *z, int n, int *pType){ - int i, j; +static i64 keywordCode(const char *z, i64 n, int *pType){ + i64 i, j; const char *zKW; assert( n>=2 ); i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127; @@ -184107,7 +186295,7 @@ SQLITE_PRIVATE i64 sqlite3GetToken(const unsigned char *z, int *tokenType){ } case CC_DOLLAR: case CC_VARALPHA: { - int n = 0; + i64 n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); *tokenType = TK_VARIABLE; @@ -184203,7 +186391,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ int tokenType; /* type of the next token */ int lastTokenParsed = -1; /* type of the previous token */ sqlite3 *db = pParse->db; /* The database connection */ - int mxSqlLen; /* Max length of an SQL string */ + i64 mxSqlLen; /* Max length of an SQL string */ Parse *pParentParse = 0; /* Outer parse context, if any */ #ifdef sqlite3Parser_ENGINEALWAYSONSTACK yyParser sEngine; /* Space to hold the Lemon-generated Parser object */ @@ -184333,7 +186521,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){ } if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){ if( pParse->zErrMsg==0 ){ - pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); + pParse->zErrMsg = sqlite3DbStrDup(db, sqlite3ErrStr(pParse->rc)); } if( (pParse->prepFlags & SQLITE_PREPARE_DONT_LOG)==0 ){ sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail); @@ -184414,7 +186602,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( sqlite3_str_append(pStr, " NULL", 5); break; } - /* Fall through */ + /* no break */ deliberate_fall_through } case TK_STRING: case TK_INTEGER: @@ -184478,7 +186666,7 @@ SQLITE_PRIVATE char *sqlite3Normalize( } case TK_SELECT: { iStartIN = 0; - /* fall through */ + /* no break */ deliberate_fall_through } default: { if( sqlite3IsIdChar(zSql[i]) ) addSpaceSeparator(pStr); @@ -185859,6 +188047,14 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){ rc = setupLookaside(db, pBuf, sz, cnt); break; } + case SQLITE_DBCONFIG_FP_DIGITS: { + int nIn = va_arg(ap, int); + int *pOut = va_arg(ap, int*); + if( nIn>3 && nIn<24 ) db->nFpDigit = (u8)nIn; + if( pOut ) *pOut = db->nFpDigit; + rc = SQLITE_OK; + break; + } default: { static const struct { int op; /* The opcode */ @@ -187414,6 +189610,9 @@ SQLITE_API void *sqlite3_wal_hook( sqlite3_mutex_leave(db->mutex); return pRet; #else + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(xCallback); + UNUSED_PARAMETER(pArg); return 0; #endif } @@ -187429,6 +189628,11 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( int *pnCkpt /* OUT: Total number of frames checkpointed */ ){ #ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(db); + UNUSED_PARAMETER(zDb); + UNUSED_PARAMETER(eMode); + UNUSED_PARAMETER(pnLog); + UNUSED_PARAMETER(pnCkpt); return SQLITE_OK; #else int rc; /* Return code */ @@ -187442,11 +189646,12 @@ SQLITE_API int sqlite3_wal_checkpoint_v2( if( pnLog ) *pnLog = -1; if( pnCkpt ) *pnCkpt = -1; + assert( SQLITE_CHECKPOINT_NOOP==-1 ); assert( SQLITE_CHECKPOINT_PASSIVE==0 ); assert( SQLITE_CHECKPOINT_FULL==1 ); assert( SQLITE_CHECKPOINT_RESTART==2 ); assert( SQLITE_CHECKPOINT_TRUNCATE==3 ); - if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ + if( eModeSQLITE_CHECKPOINT_TRUNCATE ){ /* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint ** mode: */ return SQLITE_MISUSE_BKPT; @@ -187810,6 +190015,7 @@ static const int aHardLimit[] = { SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */ SQLITE_MAX_TRIGGER_DEPTH, SQLITE_MAX_WORKER_THREADS, + SQLITE_MAX_PARSER_DEPTH, }; /* @@ -187824,6 +190030,9 @@ static const int aHardLimit[] = { #if SQLITE_MAX_SQL_LENGTH>SQLITE_MAX_LENGTH # error SQLITE_MAX_SQL_LENGTH must not be greater than SQLITE_MAX_LENGTH #endif +#if SQLITE_MAX_SQL_LENGTH>2147482624 /* 1024 less than 2^31 */ +# error SQLITE_MAX_SQL_LENGTH must not be greater than 2147482624 +#endif #if SQLITE_MAX_COMPOUND_SELECT<2 # error SQLITE_MAX_COMPOUND_SELECT must be at least 2 #endif @@ -187879,6 +190088,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH ); assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN ); assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH ); + assert( aHardLimit[SQLITE_LIMIT_PARSER_DEPTH]==SQLITE_MAX_PARSER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT); assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP ); assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG ); @@ -187888,7 +190098,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER); assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH ); assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS ); - assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) ); + assert( SQLITE_LIMIT_PARSER_DEPTH==(SQLITE_N_LIMIT-1) ); if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ @@ -188252,7 +190462,7 @@ static int openDatabase( db = sqlite3MallocZero( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; if( isThreadsafe -#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS +#if defined(SQLITE_THREAD_MISUSE_WARNINGS) || sqlite3GlobalConfig.bCoreMutex #endif ){ @@ -188273,6 +190483,7 @@ static int openDatabase( db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; db->lookaside.sz = 0; + db->nFpDigit = 17; assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); @@ -188718,6 +190929,12 @@ SQLITE_API int sqlite3_collation_needed16( */ SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){ DbClientData *p; +#ifdef SQLITE_ENABLE_API_ARMOR + if( !zName || !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif sqlite3_mutex_enter(db->mutex); for(p=db->pDbData; p; p=p->pNext){ if( strcmp(p->zName, zName)==0 ){ @@ -189575,6 +191792,17 @@ SQLITE_API int sqlite3_test_control(int op, ...){ break; } + /* sqlite3_test_control(SQLITE_TESTCTRL_ATOF, const char *z, double *p); + ** + ** Test access to the sqlite3AtoF() routine. + */ + case SQLITE_TESTCTRL_ATOF: { + const char *z = va_arg(ap,const char*); + double *pR = va_arg(ap,double*); + rc = sqlite3AtoF(z,pR); + break; + } + #if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD) /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue) ** @@ -189791,6 +192019,7 @@ SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){ } SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){ #ifdef SQLITE_OMIT_WAL + UNUSED_PARAMETER(zFilename); return 0; #else zFilename = sqlite3_filename_journal(zFilename); @@ -191164,7 +193393,16 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) -#define deliberate_fall_through +#if !defined(deliberate_fall_through) +# if defined(__has_attribute) +# if __has_attribute(fallthrough) +# define deliberate_fall_through __attribute__((fallthrough)); +# endif +# endif +#endif +#if !defined(deliberate_fall_through) +# define deliberate_fall_through +#endif /* ** Macros needed to provide flexible arrays in a portable way @@ -191562,6 +193800,15 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table*,int,int); (*(u8*)(p)&0x80) ? sqlite3Fts3GetVarint32(p, piVal) : (*piVal=*(u8*)(p), 1) \ ) +SQLITE_PRIVATE int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +); + + /* fts3.c */ SQLITE_PRIVATE void sqlite3Fts3ErrMsg(char**,const char*,...); SQLITE_PRIVATE int sqlite3Fts3PutVarint(char *, sqlite3_int64); @@ -193169,9 +195416,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist); if( !zSql ) return SQLITE_NOMEM; p->bLock++; - rc = sqlite3_prepare_v3( - p->db, zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); } @@ -194746,9 +196991,7 @@ static int fts3FilterMethod( } if( zSql ){ p->bLock++; - rc = sqlite3_prepare_v3( - p->db,zSql,-1,SQLITE_PREPARE_PERSISTENT,&pCsr->pStmt,0 - ); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, 1, &pCsr->pStmt); p->bLock--; sqlite3_free(zSql); }else{ @@ -195371,6 +197614,7 @@ static int fts3IntegrityMethod( UNUSED_PARAMETER(isQuick); rc = sqlite3Fts3IntegrityCheck(p, &bOk); + assert( pVtab->zErrMsg==0 || rc!=SQLITE_OK ); assert( rc!=SQLITE_CORRUPT_VTAB ); if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){ *pzErr = sqlite3_mprintf("unable to validate the inverted index for" @@ -197887,7 +200131,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){ pCsr->aStat[1].nDoc++; } eState = 2; - /* fall through */ + /* no break */ deliberate_fall_through case 2: if( v==0 ){ /* 0x00. Next integer will be a docid. */ @@ -201808,9 +204052,9 @@ typedef struct SegmentWriter SegmentWriter; ** incrementally. See function fts3PendingListAppend() for details. */ struct PendingList { - int nData; + sqlite3_int64 nData; char *aData; - int nSpace; + sqlite3_int64 nSpace; sqlite3_int64 iLastDocid; sqlite3_int64 iLastCol; sqlite3_int64 iLastPos; @@ -201983,6 +204227,24 @@ struct SegmentNode { #define SQL_UPDATE_LEVEL_IDX 38 #define SQL_UPDATE_LEVEL 39 +/* +** Wrapper around sqlite3_prepare_v3() to ensure that SQLITE_PREPARE_FROM_DDL +** is always set. +*/ +SQLITE_PRIVATE int sqlite3Fts3PrepareStmt( + Fts3Table *p, /* Prepare for this connection */ + const char *zSql, /* SQL to prepare */ + int bPersist, /* True to set SQLITE_PREPARE_PERSISTENT */ + int bAllowVtab, /* True to omit SQLITE_PREPARE_NO_VTAB */ + sqlite3_stmt **pp /* OUT: Prepared statement */ +){ + int f = SQLITE_PREPARE_FROM_DDL + |((bAllowVtab==0) ? SQLITE_PREPARE_NO_VTAB : 0) + |(bPersist ? SQLITE_PREPARE_PERSISTENT : 0); + + return sqlite3_prepare_v3(p->db, zSql, -1, f, pp, NULL); +} + /* ** This function is used to obtain an SQLite prepared statement handle ** for the statement identified by the second argument. If successful, @@ -202108,12 +204370,12 @@ static int fts3SqlStmt( pStmt = p->aStmt[eStmt]; if( !pStmt ){ - int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB; + int bAllowVtab = 0; char *zSql; if( eStmt==SQL_CONTENT_INSERT ){ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist); }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){ - f &= ~SQLITE_PREPARE_NO_VTAB; + bAllowVtab = 1; zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist); }else{ zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); @@ -202121,7 +204383,7 @@ static int fts3SqlStmt( if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v3(p->db, zSql, -1, f, &pStmt, NULL); + rc = sqlite3Fts3PrepareStmt(p, zSql, 1, bAllowVtab, &pStmt); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; @@ -202470,7 +204732,9 @@ static int fts3PendingTermsAddOne( pList = (PendingList *)fts3HashFind(pHash, zToken, nToken); if( pList ){ - p->nPendingData -= (pList->nData + nToken + sizeof(Fts3HashElem)); + assert( (i64)pList->nData+(i64)nToken+(i64)sizeof(Fts3HashElem) + <= (i64)p->nPendingData ); + p->nPendingData -= (int)(pList->nData + nToken + sizeof(Fts3HashElem)); } if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){ if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){ @@ -202483,7 +204747,9 @@ static int fts3PendingTermsAddOne( } } if( rc==SQLITE_OK ){ - p->nPendingData += (pList->nData + nToken + sizeof(Fts3HashElem)); + assert( (i64)p->nPendingData + pList->nData + nToken + + sizeof(Fts3HashElem) <= 0x3fffffff ); + p->nPendingData += (int)(pList->nData + nToken + sizeof(Fts3HashElem)); } return rc; } @@ -205284,7 +207550,7 @@ static int fts3DoRebuild(Fts3Table *p){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } @@ -207037,7 +209303,7 @@ SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){ if( !zSql ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); + rc = sqlite3Fts3PrepareStmt(p, zSql, 0, 1, &pStmt); sqlite3_free(zSql); } @@ -207167,7 +209433,7 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){ v = atoi(&zVal[9]); if( v>=24 && v<=p->nPgsz-35 ) p->nNodeSize = v; rc = SQLITE_OK; - }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){ + }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 11) ){ v = atoi(&zVal[11]); if( v>=64 && v<=FTS3_MAX_PENDING_DATA ) p->nMaxPendingData = v; rc = SQLITE_OK; @@ -210427,7 +212693,8 @@ struct JsonString { /* Allowed values for JsonString.eErr */ #define JSTRING_OOM 0x01 /* Out of memory */ #define JSTRING_MALFORMED 0x02 /* Malformed JSONB */ -#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */ +#define JSTRING_TOODEEP 0x04 /* JSON nested too deep */ +#define JSTRING_ERR 0x08 /* Error already sent to sqlite3_result */ /* The "subtype" set for text JSON values passed through using ** sqlite3_result_subtype() and sqlite3_value_subtype(). @@ -210442,7 +212709,10 @@ struct JsonString { #define JSON_SQL 0x02 /* Result is always SQL */ #define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */ #define JSON_ISSET 0x04 /* json_set(), not json_insert() */ -#define JSON_BLOB 0x08 /* Use the BLOB output format */ +#define JSON_AINS 0x08 /* json_array_insert(), not json_insert() */ +#define JSON_BLOB 0x10 /* Use the BLOB output format */ + +#define JSON_INSERT_TYPE(X) (((X)&0xC)>>2) /* A parsed JSON value. Lifecycle: @@ -210488,6 +212758,7 @@ struct JsonParse { #define JEDIT_REPL 2 /* Overwrite if exists */ #define JEDIT_INS 3 /* Insert if not exists */ #define JEDIT_SET 4 /* Insert or overwrite */ +#define JEDIT_AINS 5 /* array_insert() */ /* ** Maximum nesting depth of JSON for this implementation. @@ -210513,7 +212784,7 @@ struct JsonParse { **************************************************************************/ static void jsonReturnStringAsBlob(JsonString*); static int jsonArgIsJsonb(sqlite3_value *pJson, JsonParse *p); -static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*); +static u32 jsonTranslateBlobToText(JsonParse*,u32,JsonString*); static void jsonReturnParse(sqlite3_context*,JsonParse*); static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32); static void jsonParseFree(JsonParse*); @@ -210671,6 +212942,15 @@ static void jsonStringOom(JsonString *p){ jsonStringReset(p); } +/* Report JSON nested too deep +*/ +static void jsonStringTooDeep(JsonString *p){ + p->eErr |= JSTRING_TOODEEP; + assert( p->pCtx!=0 ); + sqlite3_result_error(p->pCtx, "JSON nested too deep", -1); + jsonStringReset(p); +} + /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ @@ -210960,6 +213240,7 @@ static void jsonReturnString( ){ assert( (pParse!=0)==(ctx!=0) ); assert( ctx==0 || ctx==p->pCtx ); + jsonStringTerminate(p); if( p->eErr==0 ){ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx)); if( flags & JSON_BLOB ){ @@ -210967,7 +213248,7 @@ static void jsonReturnString( }else if( p->bStatic ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, SQLITE_TRANSIENT, SQLITE_UTF8); - }else if( jsonStringTerminate(p) ){ + }else{ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){ int rc; pParse->zJson = sqlite3RCStrRef(p->zBuf); @@ -210983,11 +213264,11 @@ static void jsonReturnString( sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed, sqlite3RCStrUnref, SQLITE_UTF8); - }else{ - sqlite3_result_error_nomem(p->pCtx); } }else if( p->eErr & JSTRING_OOM ){ sqlite3_result_error_nomem(p->pCtx); + }else if( p->eErr & JSTRING_TOODEEP ){ + /* error already in p->pCtx */ }else if( p->eErr & JSTRING_MALFORMED ){ sqlite3_result_error(p->pCtx, "malformed JSON", -1); } @@ -211318,11 +213599,11 @@ static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){ /* Slow version of jsonBlobAppendNode() that first resizes the ** pParse->aBlob structure. */ -static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*); +static void jsonBlobAppendNode(JsonParse*,u8,u64,const void*); static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( JsonParse *pParse, u8 eType, - u32 szPayload, + u64 szPayload, const void *aPayload ){ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return; @@ -211342,7 +213623,7 @@ static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode( static void jsonBlobAppendNode( JsonParse *pParse, /* The JsonParse object under construction */ u8 eType, /* Node type. One of JSONB_* */ - u32 szPayload, /* Number of bytes of payload */ + u64 szPayload, /* Number of bytes of payload */ const void *aPayload /* The payload. Might be NULL */ ){ u8 *a; @@ -212198,12 +214479,8 @@ static int jsonConvertTextToBlob( */ static void jsonReturnStringAsBlob(JsonString *pStr){ JsonParse px; + assert( pStr->eErr==0 ); memset(&px, 0, sizeof(px)); - jsonStringTerminate(pStr); - if( pStr->eErr ){ - sqlite3_result_error_nomem(pStr->pCtx); - return; - } px.zJson = pStr->zBuf; px.nJson = pStr->nUsed; px.db = sqlite3_context_db_handle(pStr->pCtx); @@ -212293,7 +214570,7 @@ static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){ ** The pOut->eErr JSTRING_OOM flag is set on a OOM. */ static u32 jsonTranslateBlobToText( - const JsonParse *pParse, /* the complete parse of the JSON */ + JsonParse *pParse, /* the complete parse of the JSON */ u32 i, /* Start rendering at this index */ JsonString *pOut /* Write JSON here */ ){ @@ -212475,10 +214752,14 @@ static u32 jsonTranslateBlobToText( jsonAppendChar(pOut, '['); j = i+n; iEnd = j+sz; + if( ++pParse->iDepth > JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, ','); } + pParse->iDepth--; if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, ']'); @@ -212489,10 +214770,14 @@ static u32 jsonTranslateBlobToText( jsonAppendChar(pOut, '{'); j = i+n; iEnd = j+sz; + if( ++pParse->iDepth > JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( jeErr==0 ){ j = jsonTranslateBlobToText(pParse, j, pOut); jsonAppendChar(pOut, (x++ & 1) ? ',' : ':'); } + pParse->iDepth--; if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED; if( sz>0 ) jsonStringTrimOneChar(pOut); jsonAppendChar(pOut, '}'); @@ -212549,7 +214834,7 @@ static u32 jsonTranslateBlobToPrettyText( u32 i /* Start rendering at this index */ ){ u32 sz, n, j, iEnd; - const JsonParse *pParse = pPretty->pParse; + JsonParse *pParse = pPretty->pParse; JsonString *pOut = pPretty->pOut; n = jsonbPayloadSize(pParse, i, &sz); if( n==0 ){ @@ -212564,6 +214849,9 @@ static u32 jsonTranslateBlobToPrettyText( if( jnIndent++; + if( pPretty->nIndent >= JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } while( pOut->eErr==0 ){ jsonPrettyIndent(pPretty); j = jsonTranslateBlobToPrettyText(pPretty, j); @@ -212585,6 +214873,10 @@ static u32 jsonTranslateBlobToPrettyText( if( jnIndent++; + if( pPretty->nIndent >= JSON_MAX_DEPTH ){ + jsonStringTooDeep(pOut); + } + pParse->iDepth = pPretty->nIndent; while( pOut->eErr==0 ){ jsonPrettyIndent(pPretty); j = jsonTranslateBlobToText(pParse, j, pOut); @@ -212742,6 +215034,7 @@ static void jsonBlobEdit( u32 nIns /* Bytes of content to insert */ ){ i64 d = (i64)nIns - (i64)nDel; + assert( pParse->nBlob >= (u64)iDel + (u64)nDel ); if( d<0 && d>=(-8) && aIns!=0 && jsonBlobOverwrite(&pParse->aBlob[iDel], aIns, nIns, (int)-d) ){ @@ -212984,7 +215277,9 @@ static int jsonLabelCompare( */ #define JSON_LOOKUP_ERROR 0xffffffff #define JSON_LOOKUP_NOTFOUND 0xfffffffe -#define JSON_LOOKUP_PATHERROR 0xfffffffd +#define JSON_LOOKUP_NOTARRAY 0xfffffffd +#define JSON_LOOKUP_TOODEEP 0xfffffffc +#define JSON_LOOKUP_PATHERROR 0xfffffffb #define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR) /* Forward declaration */ @@ -213013,7 +215308,7 @@ static u32 jsonLookupStep(JsonParse*,u32,const char*,u32); static u32 jsonCreateEditSubstructure( JsonParse *pParse, /* The original JSONB that is being edited */ JsonParse *pIns, /* Populate this with the blob data to insert */ - const char *zTail /* Tail of the path that determins substructure */ + const char *zTail /* Tail of the path that determines substructure */ ){ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT }; int rc; @@ -213031,7 +215326,12 @@ static u32 jsonCreateEditSubstructure( pIns->eEdit = pParse->eEdit; pIns->nIns = pParse->nIns; pIns->aIns = pParse->aIns; + pIns->iDepth = pParse->iDepth+1; + if( pIns->iDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pIns, 0, zTail, 0); + pParse->iDepth--; pParse->oom |= pIns->oom; } return rc; /* Error code only */ @@ -213048,9 +215348,9 @@ static u32 jsonCreateEditSubstructure( ** Return one of the JSON_LOOKUP error codes if problems are seen. ** ** This routine will also modify the blob. If pParse->eEdit is one of -** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be -** made to the selected value. If an edit is performed, then the return -** value does not necessarily point to the select element. If an edit +** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, JEDIT_SET, or JEDIT_AINS, then changes +** might be made to the selected value. If an edit is performed, then the +** return value does not necessarily point to the select element. If an edit ** is performed, the return value is only useful for detecting error ** conditions. */ @@ -213076,6 +215376,13 @@ static u32 jsonLookupStep( jsonBlobEdit(pParse, iRoot, sz, 0, 0); }else if( pParse->eEdit==JEDIT_INS ){ /* Already exists, so json_insert() is a no-op */ + }else if( pParse->eEdit==JEDIT_AINS ){ + /* json_array_insert() */ + if( zPath[-1]!=']' ){ + return JSON_LOOKUP_NOTARRAY; + }else{ + jsonBlobEdit(pParse, iRoot, 0, pParse->aIns, pParse->nIns); + } }else{ /* json_set() or json_replace() */ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns); @@ -213130,7 +215437,11 @@ static u32 jsonLookupStep( n = jsonbPayloadSize(pParse, v, &sz); if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR; assert( j>0 ); + if( ++pParse->iDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pParse, v, &zPath[i], j); + pParse->iDepth--; if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } @@ -213147,6 +215458,10 @@ static u32 jsonLookupStep( JsonParse ix; /* Header of the label to be inserted */ testcase( pParse->eEdit==JEDIT_INS ); testcase( pParse->eEdit==JEDIT_SET ); + testcase( pParse->eEdit==JEDIT_AINS ); + if( pParse->eEdit==JEDIT_AINS && sqlite3_strglob("*]",&zPath[i])!=0 ){ + return JSON_LOOKUP_NOTARRAY; + } memset(&ix, 0, sizeof(ix)); ix.db = pParse->db; jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0); @@ -213174,28 +215489,32 @@ static u32 jsonLookupStep( return rc; } }else if( zPath[0]=='[' ){ + u64 kk = 0; x = pParse->aBlob[iRoot] & 0x0f; if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND; n = jsonbPayloadSize(pParse, iRoot, &sz); - k = 0; i = 1; while( sqlite3Isdigit(zPath[i]) ){ - k = k*10 + zPath[i] - '0'; + if( kk<0xffffffff ) kk = kk*10 + zPath[i] - '0'; + /* ^^^^^^^^^^--- Allow kk to be bigger than any JSON array so that + ** we get NOTFOUND instead of PATHERROR, without overflowing kk. */ i++; } if( i<2 || zPath[i]!=']' ){ if( zPath[1]=='#' ){ - k = jsonbArrayCount(pParse, iRoot); + kk = jsonbArrayCount(pParse, iRoot); i = 2; if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){ - unsigned int nn = 0; + u64 nn = 0; i = 3; do{ - nn = nn*10 + zPath[i] - '0'; + if( nn<0xffffffff ) nn = nn*10 + zPath[i] - '0'; + /* ^^^^^^^^^^--- Allow nn to be bigger than any JSON array to + ** get NOTFOUND instead of PATHERROR, without overflowing nn. */ i++; }while( sqlite3Isdigit(zPath[i]) ); - if( nn>k ) return JSON_LOOKUP_NOTFOUND; - k -= nn; + if( nn>kk ) return JSON_LOOKUP_NOTFOUND; + kk -= nn; } if( zPath[i]!=']' ){ return JSON_LOOKUP_PATHERROR; @@ -213207,21 +215526,26 @@ static u32 jsonLookupStep( j = iRoot+n; iEnd = j+sz; while( jiDepth >= JSON_MAX_DEPTH ){ + return JSON_LOOKUP_TOODEEP; + } rc = jsonLookupStep(pParse, j, &zPath[i+1], 0); + pParse->iDepth--; if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot); return rc; } - k--; + kk--; n = jsonbPayloadSize(pParse, j, &sz); if( n==0 ) return JSON_LOOKUP_ERROR; j += n+sz; } if( j>iEnd ) return JSON_LOOKUP_ERROR; - if( k>0 ) return JSON_LOOKUP_NOTFOUND; + if( kk>0 ) return JSON_LOOKUP_NOTFOUND; if( pParse->eEdit>=JEDIT_INS ){ JsonParse v; testcase( pParse->eEdit==JEDIT_INS ); + testcase( pParse->eEdit==JEDIT_AINS ); testcase( pParse->eEdit==JEDIT_SET ); rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]); if( !JSON_LOOKUP_ISERROR(rc) @@ -213359,7 +215683,7 @@ static void jsonReturnFromBlob( to_double: z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz); if( z==0 ) goto returnfromblob_oom; - rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); + rc = sqlite3AtoF(z, &r); sqlite3DbFree(db, z); if( rc<=0 ) goto returnfromblob_malformed; sqlite3_result_double(pCtx, r); @@ -213539,16 +215863,35 @@ static int jsonFunctionArgToBlob( } /* -** Generate a bad path error. +** Generate a path error. +** +** The specifics of the error are determined by the rc argument. +** +** rc error +** ----------------- ---------------------- +** JSON_LOOKUP_ARRAY "not an array" +** JSON_LOOKUP_TOODEEP "JSON nested too deep" +** JSON_LOOKUP_ERROR "malformed JSON" +** otherwise... "bad JSON path" ** ** If ctx is not NULL then push the error message into ctx and return NULL. ** If ctx is NULL, then return the text of the error message. */ static char *jsonBadPathError( sqlite3_context *ctx, /* The function call containing the error */ - const char *zPath /* The path with the problem */ + const char *zPath, /* The path with the problem */ + int rc /* Maybe JSON_LOOKUP_NOTARRAY */ ){ - char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); + char *zMsg; + if( rc==(int)JSON_LOOKUP_NOTARRAY ){ + zMsg = sqlite3_mprintf("not an array element: %Q", zPath); + }else if( rc==(int)JSON_LOOKUP_ERROR ){ + zMsg = sqlite3_mprintf("malformed JSON"); + }else if( rc==(int)JSON_LOOKUP_TOODEEP ){ + zMsg = sqlite3_mprintf("JSON path too deep"); + }else{ + zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath); + } if( ctx==0 ) return zMsg; if( zMsg ){ sqlite3_result_error(ctx, zMsg, -1); @@ -213565,13 +215908,13 @@ static char *jsonBadPathError( ** and return the result. ** ** The specific operation is determined by eEdit, which can be one -** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET. +** of JEDIT_INS, JEDIT_REPL, JEDIT_SET, or JEDIT_AINS. */ static void jsonInsertIntoBlob( sqlite3_context *ctx, int argc, sqlite3_value **argv, - int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */ + int eEdit /* JEDIT_INS, JEDIT_REPL, JEDIT_SET, JEDIT_AINS */ ){ int i; u32 rc = 0; @@ -213608,6 +215951,7 @@ static void jsonInsertIntoBlob( p->nIns = ax.nBlob; p->aIns = ax.aBlob; p->delta = 0; + p->iDepth = 0; rc = jsonLookupStep(p, 0, zPath+1, 0); } jsonParseReset(&ax); @@ -213620,11 +215964,7 @@ static void jsonInsertIntoBlob( jsonInsertIntoBlob_patherror: jsonParseFree(p); - if( rc==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - }else{ - jsonBadPathError(ctx, zPath); - } + jsonBadPathError(ctx, zPath, rc); return; } @@ -214064,10 +216404,8 @@ static void jsonArrayLengthFunc( if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, i); } eErr = 1; i = 0; @@ -214170,7 +216508,7 @@ static void jsonExtractFunc( j = jsonLookupStep(p, 0, jx.zBuf, 0); jsonStringReset(&jx); }else{ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); goto json_extract_error; } if( jnBlob ){ @@ -214201,11 +216539,8 @@ static void jsonExtractFunc( jsonAppendSeparator(&jx); jsonAppendRawNZ(&jx, "null", 4); } - }else if( j==JSON_LOOKUP_ERROR ){ - sqlite3_result_error(ctx, "malformed JSON", -1); - goto json_extract_error; }else{ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, j); goto json_extract_error; } } @@ -214229,6 +216564,7 @@ json_extract_error: #define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */ #define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */ #define JSON_MERGE_OOM 3 /* Out-of-memory condition */ +#define JSON_MERGE_TOODEEP 4 /* Nested too deep */ /* ** RFC-7396 MergePatch for two JSONB blobs. @@ -214280,7 +216616,8 @@ static int jsonMergePatch( JsonParse *pTarget, /* The JSON parser that contains the TARGET */ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */ const JsonParse *pPatch, /* The PATCH */ - u32 iPatch /* Index of PATCH in pPatch->aBlob[] */ + u32 iPatch, /* Index of PATCH in pPatch->aBlob[] */ + u32 iDepth /* Nesting depth */ ){ u8 x; /* Type of a single node */ u32 n, sz=0; /* Return values from jsonbPayloadSize() */ @@ -214389,7 +216726,8 @@ static int jsonMergePatch( /* Algorithm line 12 */ int rc, savedDelta = pTarget->delta; pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue); + if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP; + rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue, iDepth+1); if( rc ) return rc; pTarget->delta += savedDelta; } @@ -214410,7 +216748,8 @@ static int jsonMergePatch( pTarget->aBlob[iTEnd+szNew] = 0x00; savedDelta = pTarget->delta; pTarget->delta = 0; - rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue); + if( iDepth>=JSON_MAX_DEPTH ) return JSON_MERGE_TOODEEP; + rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue,iDepth+1); if( rc ) return rc; pTarget->delta += savedDelta; } @@ -214441,11 +216780,13 @@ static void jsonPatchFunc( if( pTarget==0 ) return; pPatch = jsonParseFuncArg(ctx, argv[1], 0); if( pPatch ){ - rc = jsonMergePatch(pTarget, 0, pPatch, 0); + rc = jsonMergePatch(pTarget, 0, pPatch, 0, 0); if( rc==JSON_MERGE_OK ){ jsonReturnParse(ctx, pTarget); }else if( rc==JSON_MERGE_OOM ){ sqlite3_result_error_nomem(ctx); + }else if( rc==JSON_MERGE_TOODEEP ){ + sqlite3_result_error(ctx, "JSON nested too deep", -1); }else{ sqlite3_result_error(ctx, "malformed JSON", -1); } @@ -214533,10 +216874,8 @@ static void jsonRemoveFunc( if( JSON_LOOKUP_ISERROR(rc) ){ if( rc==JSON_LOOKUP_NOTFOUND ){ continue; /* No-op */ - }else if( rc==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, rc); } goto json_remove_done; } @@ -214546,7 +216885,7 @@ static void jsonRemoveFunc( return; json_remove_patherror: - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); json_remove_done: jsonParseFree(p); @@ -214590,16 +216929,18 @@ static void jsonSetFunc( int argc, sqlite3_value **argv ){ - int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); - int bIsSet = (flags&JSON_ISSET)!=0; + int eInsType = JSON_INSERT_TYPE(flags); + static const char *azInsType[] = { "insert", "set", "array_insert" }; + static const u8 aEditType[] = { JEDIT_INS, JEDIT_SET, JEDIT_AINS }; if( argc<1 ) return; + assert( eInsType>=0 && eInsType<=2 ); if( (argc&1)==0 ) { - jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); + jsonWrongNumArgs(ctx, azInsType[eInsType]); return; } - jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS); + jsonInsertIntoBlob(ctx, argc, argv, aEditType[eInsType]); } /* @@ -214624,17 +216965,15 @@ static void jsonTypeFunc( zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) goto json_type_done; if( zPath[0]!='$' ){ - jsonBadPathError(ctx, zPath); + jsonBadPathError(ctx, zPath, 0); goto json_type_done; } i = jsonLookupStep(p, 0, zPath+1, 0); if( JSON_LOOKUP_ISERROR(i) ){ if( i==JSON_LOOKUP_NOTFOUND ){ /* no-op */ - }else if( i==JSON_LOOKUP_PATHERROR ){ - jsonBadPathError(ctx, zPath); }else{ - sqlite3_result_error(ctx, "malformed JSON", -1); + jsonBadPathError(ctx, zPath, i); } goto json_type_done; } @@ -214888,12 +217227,12 @@ static void jsonArrayStep( } static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; pStr->pCtx = ctx; - jsonAppendChar(pStr, ']'); - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); + jsonAppendRawNZ(pStr, "]", 2); + jsonStringTrimOneChar(pStr); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; @@ -214914,6 +217253,9 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); jsonStringTrimOneChar(pStr); } + }else if( flags & JSON_BLOB ){ + static const u8 emptyArray = 0x0b; + sqlite3_result_blob(ctx, &emptyArray, 1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } @@ -215010,12 +217352,12 @@ static void jsonObjectStep( } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; + int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ - int flags; - jsonAppendChar(pStr, '}'); + jsonAppendRawNZ(pStr, "}", 2); + jsonStringTrimOneChar(pStr); pStr->pCtx = ctx; - flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx)); if( pStr->eErr ){ jsonReturnString(pStr, 0, 0); return; @@ -215036,6 +217378,9 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); jsonStringTrimOneChar(pStr); } + }else if( flags & JSON_BLOB ){ + static const unsigned char emptyObject = 0x0c; + sqlite3_result_blob(ctx, &emptyObject, 1, SQLITE_STATIC); }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } @@ -215536,7 +217881,7 @@ static int jsonEachFilter( if( zRoot==0 ) return SQLITE_OK; if( zRoot[0]!='$' ){ sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } @@ -215554,7 +217899,7 @@ static int jsonEachFilter( return SQLITE_OK; } sqlite3_free(cur->pVtab->zErrMsg); - cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot); + cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot, 0); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; } @@ -215644,6 +217989,8 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){ JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc), JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc), JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc), + JFUNCTION(json_array_insert, -1,1,1, 1,0,JSON_AINS, jsonSetFunc), + JFUNCTION(jsonb_array_insert,-1,1,0, 1,1,JSON_AINS, jsonSetFunc), JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc), JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc), @@ -216753,7 +219100,17 @@ static void rtreeRelease(Rtree *pRtree){ pRtree->inWrTrans = 0; assert( pRtree->nCursor==0 ); nodeBlobReset(pRtree); - assert( pRtree->nNodeRef==0 || pRtree->bCorrupt ); + if( pRtree->nNodeRef ){ + int i; + assert( pRtree->bCorrupt ); + for(i=0; iaHash[i] ){ + RtreeNode *pNext = pRtree->aHash[i]->pNext; + sqlite3_free(pRtree->aHash[i]); + pRtree->aHash[i] = pNext; + } + } + } sqlite3_finalize(pRtree->pWriteNode); sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); @@ -218045,7 +220402,7 @@ static int AdjustTree( int iCell; cnt++; - if( NEVER(cnt>100) ){ + if( cnt>100 ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } @@ -218403,15 +220760,6 @@ static int SplitNode( rc = updateMapping(pRtree, pCell->iRowid, pLeft, iHeight); } - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pRight); - pRight = 0; - } - if( rc==SQLITE_OK ){ - rc = nodeRelease(pRtree, pLeft); - pLeft = 0; - } - splitnode_out: nodeRelease(pRtree, pRight); nodeRelease(pRtree, pLeft); @@ -218596,7 +220944,7 @@ static int rtreeInsertCell( rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ rc = AdjustTree(pRtree, pNode, pCell); - if( ALWAYS(rc==SQLITE_OK) ){ + if( rc==SQLITE_OK ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ @@ -220224,7 +222572,7 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ /* The sqlite3AtoF() routine is much much faster than atof(), if it ** is available */ double r; - (void)sqlite3AtoF((const char*)p->z, &r, j, SQLITE_UTF8); + (void)sqlite3AtoF((const char*)p->z, &r); *pVal = r; #else *pVal = (GeoCoord)atof((const char*)p->z); @@ -224163,7 +226511,7 @@ static int rbuDeltaApply( /* ERROR: copy exceeds output file size */ return -1; } - if( (int)(ofst+cnt) > lenSrc ){ + if( (u64)ofst+(u64)cnt > (u64)lenSrc ){ /* ERROR: copy extends past end of input */ return -1; } @@ -225809,8 +228157,8 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ /* If necessary, grow the pIter->aIdxCol[] array */ if( iIdxCol==nIdxAlloc ){ - RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc( - pIter->aIdxCol, (nIdxAlloc+16)*sizeof(RbuSpan) + RbuSpan *aIdxCol = (RbuSpan*)sqlite3_realloc64( + pIter->aIdxCol, nIdxAlloc*sizeof(RbuSpan) + 16*sizeof(RbuSpan) ); if( aIdxCol==0 ){ rc = SQLITE_NOMEM; @@ -230483,6 +232831,7 @@ struct carray_bind { int nData; /* Number of elements */ int mFlags; /* Control flags */ void (*xDel)(void*); /* Destructor for aData */ + void *pDel; /* Alternative argument to xDel() */ }; @@ -230815,7 +233164,7 @@ static sqlite3_module carrayModule = { static void carrayBindDel(void *pPtr){ carray_bind *p = (carray_bind*)pPtr; if( p->xDel!=SQLITE_STATIC ){ - p->xDel(p->aData); + p->xDel(p->pDel); } sqlite3_free(p); } @@ -230823,14 +233172,26 @@ static void carrayBindDel(void *pPtr){ /* ** Invoke this interface in order to bind to the single-argument ** version of CARRAY(). +** +** pStmt The prepared statement to which to bind +** idx The index of the parameter of pStmt to which to bind +** aData The data to be bound +** nData The number of elements in aData +** mFlags One of SQLITE_CARRAY_xxxx indicating datatype of aData +** xDestroy Destructor for pDestroy or aData if pDestroy==NULL. +** pDestroy Invoke xDestroy on this pointer if not NULL +** +** The destructor is called pDestroy if pDestroy!=NULL, or against +** aData if pDestroy==NULL. */ -SQLITE_API int sqlite3_carray_bind( +SQLITE_API int sqlite3_carray_bind_v2( sqlite3_stmt *pStmt, int idx, void *aData, int nData, int mFlags, - void (*xDestroy)(void*) + void (*xDestroy)(void*), + void *pDestroy ){ carray_bind *pNew = 0; int i; @@ -230907,20 +233268,38 @@ SQLITE_API int sqlite3_carray_bind( memcpy(pNew->aData, aData, sz); } pNew->xDel = sqlite3_free; + pNew->pDel = pNew->aData; }else{ pNew->aData = aData; pNew->xDel = xDestroy; + pNew->pDel = pDestroy; } return sqlite3_bind_pointer(pStmt, idx, pNew, "carray-bind", carrayBindDel); carray_bind_error: if( xDestroy!=SQLITE_STATIC && xDestroy!=SQLITE_TRANSIENT ){ - xDestroy(aData); + xDestroy(pDestroy); } sqlite3_free(pNew); return rc; } +/* +** Invoke this interface in order to bind to the single-argument +** version of CARRAY(). Same as sqlite3_carray_bind_v2() with the +** pDestroy parameter set to NULL. +*/ +SQLITE_API int sqlite3_carray_bind( + sqlite3_stmt *pStmt, + int idx, + void *aData, + int nData, + int mFlags, + void (*xDestroy)(void*) +){ + return sqlite3_carray_bind_v2(pStmt,idx,aData,nData,mFlags,xDestroy,aData); +} + /* ** Invoke this routine to register the carray() function. */ @@ -231283,6 +233662,21 @@ static int sessionVarintGet(const u8 *aBuf, int *piVal){ return getVarint32(aBuf, *piVal); } +/* +** Read a varint value from buffer aBuf[], size nBuf bytes, into *piVal. +** Return the number of bytes read. +*/ +static int sessionVarintGetSafe(const u8 *aBuf, int nBuf, int *piVal){ + u8 aCopy[9]; + const u8 *aRead = aBuf; + memset(aCopy, 0, sizeof(aCopy)); + if( nBuf> 0) & 0xFF; } +/* +** Write a double value to the buffer aBuf[]. +*/ +static void sessionPutDouble(u8 *aBuf, double r){ + /* TODO: SQLite does something special to deal with mixed-endian + ** floating point values (e.g. ARM7). This code probably should + ** too. */ + u64 i; + assert( sizeof(double)==8 && sizeof(u64)==8 ); + memcpy(&i, &r, 8); + sessionPutI64(aBuf, i); +} + /* ** This function is used to serialize the contents of value pValue (see ** comment titled "RECORD FORMAT" above). @@ -231348,16 +233755,13 @@ static int sessionSerializeValue( /* TODO: SQLite does something special to deal with mixed-endian ** floating point values (e.g. ARM7). This code probably should ** too. */ - u64 i; if( eType==SQLITE_INTEGER ){ - i = (u64)sqlite3_value_int64(pValue); + u64 i = (u64)sqlite3_value_int64(pValue); + sessionPutI64(&aBuf[1], i); }else{ - double r; - assert( sizeof(double)==8 && sizeof(u64)==8 ); - r = sqlite3_value_double(pValue); - memcpy(&i, &r, 8); + double r = sqlite3_value_double(pValue); + sessionPutDouble(&aBuf[1], r); } - sessionPutI64(&aBuf[1], i); } nByte = 9; break; @@ -231577,14 +233981,10 @@ static unsigned int sessionChangeHash( int isPK = pTab->abPK[i]; if( bPkOnly && isPK==0 ) continue; - /* It is not possible for eType to be SQLITE_NULL here. The session - ** module does not record changes for rows with NULL values stored in - ** primary key columns. */ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT || eType==SQLITE_TEXT || eType==SQLITE_BLOB || eType==SQLITE_NULL || eType==0 ); - assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) ); if( isPK ){ a++; @@ -231592,12 +233992,16 @@ static unsigned int sessionChangeHash( if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ h = sessionHashAppendI64(h, sessionGetI64(a)); a += 8; - }else{ + }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int n; a += sessionVarintGet(a, &n); h = sessionHashAppendBlob(h, n, a); a += n; } + /* It should not be possible for eType to be SQLITE_NULL or 0x00 here, + ** as the session module does not record changes for rows with NULL + ** values stored in primary key columns. But a corrupt changesets + ** may contain such a value. */ }else{ a += sessionSerialLen(a); } @@ -232289,9 +234693,7 @@ static void sessionUpdateOneChange( case SQLITE_FLOAT: { double rVal = sqlite3_column_double(pDflt, iField); - i64 iVal = 0; - memcpy(&iVal, &rVal, sizeof(rVal)); - sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal); + sessionPutDouble(&pNew->aRecord[pNew->nRecord], rVal); pNew->nRecord += 8; break; } @@ -233548,15 +235950,14 @@ static void sessionAppendCol( int eType = sqlite3_column_type(pStmt, iCol); sessionAppendByte(p, (u8)eType, pRc); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ - sqlite3_int64 i; u8 aBuf[8]; if( eType==SQLITE_INTEGER ){ - i = sqlite3_column_int64(pStmt, iCol); + sqlite3_int64 i = sqlite3_column_int64(pStmt, iCol); + sessionPutI64(aBuf, i); }else{ double r = sqlite3_column_double(pStmt, iCol); - memcpy(&i, &r, 8); + sessionPutDouble(aBuf, r); } - sessionPutI64(aBuf, i); sessionAppendBlob(p, aBuf, 8, pRc); } if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){ @@ -234006,10 +236407,13 @@ static int sessionGenerateChangeset( } if( pSession->rc ) return pSession->rc; - rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); - if( rc!=SQLITE_OK ) return rc; sqlite3_mutex_enter(sqlite3_db_mutex(db)); + rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0); + if( rc!=SQLITE_OK ){ + sqlite3_mutex_leave(sqlite3_db_mutex(db)); + return rc; + } for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){ if( pTab->nEntry ){ @@ -234492,7 +236896,8 @@ static int sessionReadRecord( u8 *aVal = &pIn->aData[pIn->iNext]; if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int nByte; - pIn->iNext += sessionVarintGet(aVal, &nByte); + int nRem = pIn->nData - pIn->iNext; + pIn->iNext += sessionVarintGetSafe(aVal, nRem, &nByte); rc = sessionInputBuffer(pIn, nByte); if( rc==SQLITE_OK ){ if( nByte<0 || nByte>pIn->nData-pIn->iNext ){ @@ -234545,7 +236950,8 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ rc = sessionInputBuffer(pIn, 9); if( rc==SQLITE_OK ){ - nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol); + int nBuf = pIn->nData - pIn->iNext; + nRead += sessionVarintGetSafe(&pIn->aData[pIn->iNext], nBuf, &nCol); /* The hard upper limit for the number of columns in an SQLite ** database table is, according to sqliteLimit.h, 32676. So ** consider any table-header that purports to have more than 65536 @@ -234565,8 +236971,15 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){ while( (pIn->iNext + nRead)nData && pIn->aData[pIn->iNext + nRead] ){ nRead++; } + + /* Break out of the loop if if the nul-terminator byte has been found. + ** Otherwise, read some more input data and keep seeking. If there is + ** no more input data, consider the changeset corrupt. */ if( (pIn->iNext + nRead)nData ) break; rc = sessionInputBuffer(pIn, nRead + 100); + if( rc==SQLITE_OK && (pIn->iNext + nRead)>=pIn->nData ){ + rc = SQLITE_CORRUPT_BKPT; + } } *pnByte = nRead+1; return rc; @@ -234587,7 +237000,7 @@ static int sessionChangesetBufferRecord( int *pnByte /* OUT: Size of record in bytes */ ){ int rc = SQLITE_OK; - int nByte = 0; + i64 nByte = 0; int i; for(i=0; rc==SQLITE_OK && iaData[pIn->iNext + nByte++]; if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ int n; - nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n); + int nRem = pIn->nData - (pIn->iNext + nByte); + nByte += sessionVarintGetSafe(&pIn->aData[pIn->iNext+nByte], nRem, &n); nByte += n; rc = sessionInputBuffer(pIn, nByte); }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ nByte += 8; } } + if( (pIn->iNext+nByte)>pIn->nData ){ + rc = SQLITE_CORRUPT_BKPT; + } } *pnByte = nByte; return rc; @@ -234698,10 +237115,10 @@ static int sessionChangesetNextOne( memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2); } - /* Make sure the buffer contains at least 10 bytes of input data, or all - ** remaining data if there are less than 10 bytes available. This is - ** sufficient either for the 'T' or 'P' byte and the varint that follows - ** it, or for the two single byte values otherwise. */ + /* Make sure the buffer contains at least 2 bytes of input data, or all + ** remaining data if there are less than 2 bytes available. This is + ** sufficient either for the 'T' or 'P' byte that begins a new table, + ** or for the "op" and "bIndirect" single bytes otherwise. */ p->rc = sessionInputBuffer(&p->in, 2); if( p->rc!=SQLITE_OK ) return p->rc; @@ -234731,11 +237148,13 @@ static int sessionChangesetNextOne( return (p->rc = SQLITE_CORRUPT_BKPT); } - p->op = op; - p->bIndirect = p->in.aData[p->in.iNext++]; - if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){ + if( (op!=SQLITE_UPDATE && op!=SQLITE_DELETE && op!=SQLITE_INSERT) + || (p->in.iNext>=p->in.nData) + ){ return (p->rc = SQLITE_CORRUPT_BKPT); } + p->op = op; + p->bIndirect = p->in.aData[p->in.iNext++]; if( paRec ){ int nVal; /* Number of values to buffer */ @@ -236583,6 +239002,21 @@ SQLITE_API int sqlite3changeset_apply_strm( ); } +/* +** The parts of the sqlite3_changegroup structure used by the +** sqlite3changegroup_change_xxx() APIs. +*/ +typedef struct ChangeData ChangeData; +struct ChangeData { + SessionTable *pTab; + int bIndirect; + int eOp; + + int nBufAlloc; + SessionBuffer *aBuf; + SessionBuffer record; +}; + /* ** sqlite3_changegroup handle. */ @@ -236594,12 +239028,17 @@ struct sqlite3_changegroup { sqlite3 *db; /* Configured by changegroup_schema() */ char *zDb; /* Configured by changegroup_schema() */ + ChangeData cd; /* Used by changegroup_change_xxx() APIs. */ }; /* ** This function is called to merge two changes to the same row together as ** part of an sqlite3changeset_concat() operation. A new change object is ** allocated and a pointer to it stored in *ppNew. +** +** Because they have been vetted by sqlite3changegroup_add() or similar, +** both the aRec[] change and the pExist change are safe to use without +** checking for buffer overflows. */ static int sessionChangeMerge( SessionTable *pTab, /* Table structure */ @@ -236740,7 +239179,7 @@ static int sessionChangeMerge( memcpy(aCsr, aRec, nRec); aCsr += nRec; }else{ - if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){ + if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist,0,aRec,0) ){ sqlite3_free(pNew); pNew = 0; } @@ -236833,15 +239272,14 @@ static int sessionChangesetExtendRecord( switch( eType ){ case SQLITE_FLOAT: case SQLITE_INTEGER: { - i64 iVal; - if( eType==SQLITE_INTEGER ){ - iVal = sqlite3_column_int64(pTab->pDfltStmt, ii); - }else{ - double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii); - memcpy(&iVal, &rVal, sizeof(i64)); - } if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){ - sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + if( eType==SQLITE_INTEGER ){ + sqlite3_int64 iVal = sqlite3_column_int64(pTab->pDfltStmt, ii); + sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal); + }else{ + double rVal = sqlite3_column_double(pTab->pDfltStmt, ii); + sessionPutDouble(&pOut->aBuf[pOut->nBuf], rVal); + } pOut->nBuf += 8; } break; @@ -236912,13 +239350,19 @@ static int sessionChangesetFindTable( int nCol = 0; *ppTab = 0; - sqlite3changeset_pk(pIter, &abPK, &nCol); /* Search the list for an existing table */ for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){ if( 0==sqlite3_strnicmp(pTab->zName, zTab, nTab+1) ) break; } + + if( pIter ){ + sqlite3changeset_pk(pIter, &abPK, &nCol); + }else if( !pTab && !pGrp->db ){ + return SQLITE_OK; + } + /* If one was not found above, create a new table now */ if( !pTab ){ SessionTable **ppNew; @@ -236930,15 +239374,17 @@ static int sessionChangesetFindTable( memset(pTab, 0, sizeof(SessionTable)); pTab->nCol = nCol; pTab->abPK = (u8*)&pTab[1]; - memcpy(pTab->abPK, abPK, nCol); + if( nCol>0 ){ + memcpy(pTab->abPK, abPK, nCol); + } pTab->zName = (char*)&pTab->abPK[nCol]; memcpy(pTab->zName, zTab, nTab+1); if( pGrp->db ){ pTab->nCol = 0; rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb); - if( rc ){ - assert( pTab->azCol==0 ); + if( rc || pTab->nCol==0 ){ + sqlite3_free(pTab->azCol); sqlite3_free(pTab); return rc; } @@ -236953,7 +239399,7 @@ static int sessionChangesetFindTable( } /* Check that the table is compatible. */ - if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){ + if( pIter && !sessionChangesetCheckCompat(pTab, nCol, abPK) ){ rc = SQLITE_SCHEMA; } @@ -236962,44 +239408,27 @@ static int sessionChangesetFindTable( } /* -** Add the change currently indicated by iterator pIter to the hash table -** belonging to changegroup pGrp. +** Add a single change to the changegroup pGrp. */ static int sessionOneChangeToHash( - sqlite3_changegroup *pGrp, - sqlite3_changeset_iter *pIter, - int bRebase + sqlite3_changegroup *pGrp, /* Changegroup to update */ + SessionTable *pTab, /* Table change pertains to */ + int op, /* One of SQLITE_INSERT, UPDATE, DELETE */ + int bIndirect, /* True to flag change as "indirect" */ + int nCol, /* Number of columns in record(s) */ + u8 *aRec, /* Serialized change record(s) */ + int nRec, /* Size of aRec[] in bytes */ + int bRebase /* True if this is a rebase blob */ ){ int rc = SQLITE_OK; - int nCol = 0; - int op = 0; int iHash = 0; - int bIndirect = 0; SessionChange *pChange = 0; SessionChange *pExist = 0; SessionChange **pp = 0; - SessionTable *pTab = 0; - u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; - int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; assert( nRec>0 ); - /* Ensure that only changesets, or only patchsets, but not a mixture - ** of both, are being combined. It is an error to try to combine a - ** changeset and a patchset. */ - if( pGrp->pList==0 ){ - pGrp->bPatch = pIter->bPatchset; - }else if( pIter->bPatchset!=pGrp->bPatch ){ - rc = SQLITE_ERROR; - } - - if( rc==SQLITE_OK ){ - const char *zTab = 0; - sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); - rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab); - } - - if( rc==SQLITE_OK && nColnCol ){ + if( nColnCol ){ SessionBuffer *pBuf = &pGrp->rec; rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, pBuf); aRec = pBuf->aBuf; @@ -237007,7 +239436,7 @@ static int sessionOneChangeToHash( assert( pGrp->db ); } - if( rc==SQLITE_OK && sessionGrowHash(0, pIter->bPatchset, pTab) ){ + if( rc==SQLITE_OK && sessionGrowHash(0, pGrp->bPatch, pTab) ){ rc = SQLITE_NOMEM; } @@ -237015,12 +239444,12 @@ static int sessionOneChangeToHash( /* Search for existing entry. If found, remove it from the hash table. ** Code below may link it back in. */ iHash = sessionChangeHash( - pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange + pTab, (pGrp->bPatch && op==SQLITE_DELETE), aRec, pTab->nChange ); for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){ int bPkOnly1 = 0; int bPkOnly2 = 0; - if( pIter->bPatchset ){ + if( pGrp->bPatch ){ bPkOnly1 = (*pp)->op==SQLITE_DELETE; bPkOnly2 = op==SQLITE_DELETE; } @@ -237035,7 +239464,7 @@ static int sessionOneChangeToHash( if( rc==SQLITE_OK ){ rc = sessionChangeMerge(pTab, bRebase, - pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange + pGrp->bPatch, pExist, op, bIndirect, aRec, nRec, &pChange ); } if( rc==SQLITE_OK && pChange ){ @@ -237044,6 +239473,47 @@ static int sessionOneChangeToHash( pTab->nEntry++; } + return rc; +} + +/* +** Add the change currently indicated by iterator pIter to the hash table +** belonging to changegroup pGrp. +*/ +static int sessionOneChangeIterToHash( + sqlite3_changegroup *pGrp, + sqlite3_changeset_iter *pIter, + int bRebase +){ + u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; + int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; + const char *zTab = 0; + int nCol = 0; + int op = 0; + int bIndirect = 0; + int rc = SQLITE_OK; + SessionTable *pTab = 0; + + /* Ensure that only changesets, or only patchsets, but not a mixture + ** of both, are being combined. It is an error to try to combine a + ** changeset and a patchset. */ + if( pGrp->pList==0 ){ + pGrp->bPatch = pIter->bPatchset; + }else if( pIter->bPatchset!=pGrp->bPatch ){ + rc = SQLITE_ERROR; + } + + if( rc==SQLITE_OK ){ + sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); + rc = sessionChangesetFindTable(pGrp, zTab, pIter, &pTab); + } + + if( rc==SQLITE_OK ){ + rc = sessionOneChangeToHash( + pGrp, pTab, op, bIndirect, nCol, aRec, nRec, bRebase + ); + } + if( rc==SQLITE_OK ) rc = pIter->rc; return rc; } @@ -237063,7 +239533,7 @@ static int sessionChangesetToHash( pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ - rc = sessionOneChangeToHash(pGrp, pIter, bRebase); + rc = sessionOneChangeIterToHash(pGrp, pIter, bRebase); if( rc!=SQLITE_OK ) break; } @@ -237153,6 +239623,33 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){ return rc; } +/* +** Configure a changegroup object. +*/ +SQLITE_API int sqlite3changegroup_config( + sqlite3_changegroup *pGrp, + int op, + void *pArg +){ + int rc = SQLITE_OK; + + switch( op ){ + case SQLITE_CHANGEGROUP_CONFIG_PATCHSET: { + int arg = *(int*)pArg; + if( pGrp->pList==0 && arg>=0 ){ + pGrp->bPatch = (arg>0); + } + *(int*)pArg = pGrp->bPatch; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + + return rc; +} + /* ** Provide a database schema to the changegroup object. */ @@ -237211,7 +239708,7 @@ SQLITE_API int sqlite3changegroup_add_change( rc = SQLITE_ERROR; }else{ pIter->in.bNoDiscard = 1; - rc = sessionOneChangeToHash(pGrp, pIter, 0); + rc = sessionOneChangeIterToHash(pGrp, pIter, 0); } return rc; } @@ -237263,6 +239760,12 @@ SQLITE_API int sqlite3changegroup_output_strm( */ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ + int ii; + for(ii=0; iicd.nBufAlloc; ii++){ + sqlite3_free(pGrp->cd.aBuf[ii].aBuf); + } + sqlite3_free(pGrp->cd.record.aBuf); + sqlite3_free(pGrp->cd.aBuf); sqlite3_free(pGrp->zDb); sessionDeleteTable(0, pGrp->pList); sqlite3_free(pGrp->rec.aBuf); @@ -237693,6 +240196,328 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){ return rc; } +/* +** Begin adding a change to a changegroup object. +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup *pGrp, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +){ + SessionTable *pTab = 0; + int rc = SQLITE_OK; + + if( pGrp->cd.pTab ){ + rc = SQLITE_MISUSE; + }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_UPDATE && eOp!=SQLITE_DELETE ){ + rc = SQLITE_ERROR; + }else{ + rc = sessionChangesetFindTable(pGrp, zTab, 0, &pTab); + } + if( rc==SQLITE_OK ){ + if( pTab==0 ){ + if( pzErr ){ + *pzErr = sqlite3_mprintf("no such table: %s", zTab); + } + rc = SQLITE_ERROR; + }else{ + int nReq = pTab->nCol * (eOp==SQLITE_UPDATE ? 2 : 1); + pGrp->cd.pTab = pTab; + pGrp->cd.eOp = eOp; + pGrp->cd.bIndirect = bIndirect; + + if( pGrp->cd.nBufAlloccd.aBuf, nReq * sizeof(SessionBuffer) + ); + if( aBuf==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(&aBuf[pGrp->cd.nBufAlloc], 0, + sizeof(SessionBuffer) * (nReq - pGrp->cd.nBufAlloc) + ); + pGrp->cd.aBuf = aBuf; + pGrp->cd.nBufAlloc = nReq; + } + } + +#ifdef SQLITE_DEBUG + { + /* Assert that all column values are currently undefined */ + int ii; + for(ii=0; iicd.nBufAlloc; ii++){ + assert( pGrp->cd.aBuf[ii].nBuf==0 ); + } + } +#endif + } + } + + return rc; +} + +/* +** This function does processing common to the _change_int64(), _change_text() +** and other similar APIs. +*/ +static int checkChangeParams( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + sqlite3_int64 nReq, + SessionBuffer **ppBuf +){ + int rc = SQLITE_OK; + if( pGrp->cd.pTab==0 ){ + rc = SQLITE_MISUSE; + }else if( iCol<0 || iCol>=pGrp->cd.pTab->nCol ){ + rc = SQLITE_RANGE; + }else if( + (bNew && pGrp->cd.eOp==SQLITE_DELETE) + || (!bNew && pGrp->cd.eOp==SQLITE_INSERT) + ){ + rc = SQLITE_ERROR; + }else{ + SessionBuffer *pBuf = &pGrp->cd.aBuf[iCol]; + if( pGrp->cd.eOp==SQLITE_UPDATE && bNew ){ + pBuf += pGrp->cd.pTab->nCol; + } + pBuf->nBuf = 0; + sessionBufferGrow(pBuf, nReq, &rc); + pBuf->nBuf = nReq; + *ppBuf = pBuf; + } + return rc; +} + +/* +** Configure the change currently under construction with an integer value. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + sqlite3_int64 iVal +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_INTEGER; + sessionPutI64(&pBuf->aBuf[1], iVal); + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a null value. +*/ +SQLITE_API int sqlite3changegroup_change_null( + sqlite3_changegroup *pGrp, + int bNew, + int iCol +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 1, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_NULL; + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a real value. +*/ +SQLITE_API int sqlite3changegroup_change_double( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + double fVal +){ + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, 9, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_FLOAT; + sessionPutDouble(&pBuf->aBuf[1], fVal); + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a text value. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + const char *pVal, + int nVal +){ + int nText = nVal>=0 ? nVal : strlen(pVal); + sqlite3_int64 nByte = 1 + sessionVarintLen(nText) + nText; + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_TEXT; + pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nText)); + memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nText); + pBuf->nBuf += nText; + + return SQLITE_OK; +} + +/* +** Configure the change currently under construction with a blob value. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup *pGrp, + int bNew, + int iCol, + const void *pVal, + int nVal +){ + sqlite3_int64 nByte = 1 + sessionVarintLen(nVal) + nVal; + int rc = SQLITE_OK; + SessionBuffer *pBuf = 0; + + if( SQLITE_OK!=(rc = checkChangeParams(pGrp, bNew, iCol, nByte, &pBuf)) ){ + return rc; + } + + pBuf->aBuf[0] = SQLITE_BLOB; + pBuf->nBuf = (1 + sessionVarintPut(&pBuf->aBuf[1], nVal)); + memcpy(&pBuf->aBuf[pBuf->nBuf], pVal, nVal); + pBuf->nBuf += nVal; + + return SQLITE_OK; +} + +/* +** Finish any change currently being constructed by the changegroup object. +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup *pGrp, + int bDiscard, + char **pzErr +){ + int rc = SQLITE_OK; + if( pGrp->cd.pTab ){ + SessionBuffer *aBuf = pGrp->cd.aBuf; + int ii; + + if( bDiscard==0 ){ + int nBuf = pGrp->cd.pTab->nCol; + u8 eUndef = SQLITE_NULL; + if( pGrp->cd.eOp==SQLITE_UPDATE ){ + for(ii=0; iicd.pTab->abPK[ii] ){ + if( aBuf[ii].nBuf<=1 ){ + *pzErr = sqlite3_mprintf( + "invalid change: %s value in PK of old.* record", + aBuf[ii].nBuf==1 ? "null" : "undefined" + ); + rc = SQLITE_ERROR; + break; + }else if( aBuf[ii + nBuf].nBuf>0 ){ + *pzErr = sqlite3_mprintf( + "invalid change: defined value in PK of new.* record" + ); + rc = SQLITE_ERROR; + break; + } + }else + if( pGrp->bPatch==0 && (aBuf[ii].nBuf>0)!=(aBuf[ii+nBuf].nBuf>0) ){ + *pzErr = sqlite3_mprintf( + "invalid change: column %d " + "- old.* value is %sdefined but new.* is %sdefined", + ii, aBuf[ii].nBuf ? "" : "un", aBuf[ii+nBuf].nBuf ? "" : "un" + ); + rc = SQLITE_ERROR; + break; + } + } + eUndef = 0x00; + if( pGrp->bPatch==0 ) nBuf = nBuf * 2; + }else{ + for(ii=0; iicd.pTab->abPK[ii]; + if( (pGrp->cd.eOp==SQLITE_INSERT || pGrp->bPatch==0 || isPK) + && aBuf[ii].nBuf==0 + ){ + *pzErr = sqlite3_mprintf( + "invalid change: column %d is undefined", ii + ); + rc = SQLITE_ERROR; + break; + } + if( aBuf[ii].nBuf==1 && isPK ){ + *pzErr = sqlite3_mprintf( + "invalid change: null value in PK" + ); + rc = SQLITE_ERROR; + break; + } + } + } + + pGrp->cd.record.nBuf = 0; + for(ii=0; iicd.aBuf[ii]; + if( pGrp->bPatch ){ + if( pGrp->cd.pTab->abPK[ii]==0 ){ + if( pGrp->cd.eOp==SQLITE_UPDATE ){ + p += pGrp->cd.pTab->nCol; + }else if( pGrp->cd.eOp==SQLITE_DELETE ){ + continue; + } + } + } + if( 0==sessionBufferGrow(&pGrp->cd.record, p->nBuf?p->nBuf:1, &rc) ){ + if( p->nBuf ){ + memcpy(&pGrp->cd.record.aBuf[pGrp->cd.record.nBuf],p->aBuf,p->nBuf); + pGrp->cd.record.nBuf += p->nBuf; + }else{ + pGrp->cd.record.aBuf[pGrp->cd.record.nBuf++] = eUndef; + } + } + } + if( rc==SQLITE_OK ){ + rc = sessionOneChangeToHash( + pGrp, pGrp->cd.pTab, + pGrp->cd.eOp, pGrp->cd.bIndirect, pGrp->cd.pTab->nCol, + pGrp->cd.record.aBuf, pGrp->cd.record.nBuf, 0 + ); + } + } + + /* Reset all aBuf[] entries to "undefined". */ + { + int nZero = pGrp->cd.pTab->nCol; + if( pGrp->cd.eOp==SQLITE_UPDATE ) nZero += nZero; + for(ii=0; iicd.aBuf[ii].nBuf = 0; + } + } + pGrp->cd.pTab = 0; + } + + return rc; +} + #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ /************** End of sqlite3session.c **************************************/ @@ -239623,14 +242448,22 @@ typedef union { #define sqlite3Fts5ParserARG_PARAM ,pParse #define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse=fts5yypParser->pParse; #define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse=pParse; +#undef fts5YYREALLOC #define fts5YYREALLOC realloc +#undef fts5YYFREE #define fts5YYFREE free +#undef fts5YYDYNSTACK #define fts5YYDYNSTACK 0 +#undef fts5YYSIZELIMIT +#define sqlite3Fts5ParserCTX(P) 0 #define sqlite3Fts5ParserCTX_SDECL #define sqlite3Fts5ParserCTX_PDECL #define sqlite3Fts5ParserCTX_PARAM #define sqlite3Fts5ParserCTX_FETCH #define sqlite3Fts5ParserCTX_STORE +#undef fts5YYERRORSYMBOL +#undef fts5YYERRSYMDT +#undef fts5YYFALLBACK #define fts5YYNSTATE 35 #define fts5YYNRULE 28 #define fts5YYNRULE_WITH_ACTION 28 @@ -239955,15 +242788,24 @@ static int fts5yyGrowStack(fts5yyParser *p){ int newSize; int idx; fts5yyStackEntry *pNew; +#ifdef fts5YYSIZELIMIT + int nLimit = fts5YYSIZELIMIT(sqlite3Fts5ParserCTX(p)); +#endif newSize = oldSize*2 + 100; +#ifdef fts5YYSIZELIMIT + if( newSize>nLimit ){ + newSize = nLimit; + if( newSize<=oldSize ) return 1; + } +#endif idx = (int)(p->fts5yytos - p->fts5yystack); if( p->fts5yystack==p->fts5yystk0 ){ - pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0])); + pNew = fts5YYREALLOC(0, newSize*sizeof(pNew[0]), sqlite3Fts5ParserCTX(p)); if( pNew==0 ) return 1; memcpy(pNew, p->fts5yystack, oldSize*sizeof(pNew[0])); }else{ - pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0])); + pNew = fts5YYREALLOC(p->fts5yystack, newSize*sizeof(pNew[0]), sqlite3Fts5ParserCTX(p)); if( pNew==0 ) return 1; } p->fts5yystack = pNew; @@ -240143,7 +242985,9 @@ static void sqlite3Fts5ParserFinalize(void *p){ } #if fts5YYGROWABLESTACK - if( pParser->fts5yystack!=pParser->fts5yystk0 ) fts5YYFREE(pParser->fts5yystack); + if( pParser->fts5yystack!=pParser->fts5yystk0 ){ + fts5YYFREE(pParser->fts5yystack, sqlite3Fts5ParserCTX(pParser)); + } #endif } @@ -241425,7 +244269,7 @@ static void fts5SnippetFunction( iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); - aSeen = sqlite3_malloc(nPhrase); + aSeen = sqlite3_malloc64(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } @@ -242080,7 +244924,7 @@ static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){ if( nIn<0 ){ nIn = (int)strlen(pIn); } - zRet = (char*)sqlite3_malloc(nIn+1); + zRet = (char*)sqlite3_malloc64((i64)nIn+1); if( zRet ){ memcpy(zRet, pIn, nIn); zRet[nIn] = '\0'; @@ -242780,7 +245624,7 @@ static int sqlite3Fts5ConfigParse( sqlite3_int64 nByte; int bUnindexed = 0; /* True if there are one or more UNINDEXED */ - *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); + *ppOut = pRet = (Fts5Config*)sqlite3_malloc64(sizeof(Fts5Config)); if( pRet==0 ) return SQLITE_NOMEM; memset(pRet, 0, sizeof(Fts5Config)); pRet->pGlobal = pGlobal; @@ -243328,8 +246172,6 @@ static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ va_end(ap); } - - /* ** 2014 May 31 ** @@ -243646,7 +246488,7 @@ static int sqlite3Fts5ExprNew( assert( sParse.rc!=SQLITE_OK || sParse.zErr==0 ); if( sParse.rc==SQLITE_OK ){ - *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); + *ppNew = pNew = sqlite3_malloc64(sizeof(Fts5Expr)); if( pNew==0 ){ sParse.rc = SQLITE_NOMEM; sqlite3Fts5ParseNodeFree(sParse.pExpr); @@ -243798,7 +246640,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){ p2->pRoot = 0; if( sParse.rc==SQLITE_OK ){ - Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc( + Fts5ExprPhrase **ap = (Fts5ExprPhrase**)sqlite3_realloc64( p1->apExprPhrase, nPhrase * sizeof(Fts5ExprPhrase*) ); if( ap==0 ){ @@ -246710,7 +249552,7 @@ static int sqlite3Fts5HashNew(Fts5Config *pConfig, Fts5Hash **ppNew, int *pnByte int rc = SQLITE_OK; Fts5Hash *pNew; - *ppNew = pNew = (Fts5Hash*)sqlite3_malloc(sizeof(Fts5Hash)); + *ppNew = pNew = (Fts5Hash*)sqlite3_malloc64(sizeof(Fts5Hash)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -249303,7 +252145,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){ /* If necessary, grow the pIter->aRowidOffset[] array. */ if( iRowidOffset>=pIter->nRowidOffset ){ - int nNew = pIter->nRowidOffset + 8; + i64 nNew = pIter->nRowidOffset + 8; int *aNew = (int*)sqlite3_realloc64(pIter->aRowidOffset,nNew*sizeof(int)); if( aNew==0 ){ p->rc = SQLITE_NOMEM; @@ -252450,7 +255292,7 @@ static void fts5DoSecureDelete( int iSegid = pSeg->pSeg->iSegid; u8 *aPg = pSeg->pLeaf->p; int nPg = pSeg->pLeaf->nn; - int iPgIdx = pSeg->pLeaf->szLeaf; + int iPgIdx = pSeg->pLeaf->szLeaf; /* Offset of page footer */ u64 iDelta = 0; int iNextOff = 0; @@ -252529,7 +255371,7 @@ static void fts5DoSecureDelete( iSOP += fts5GetVarint32(&aPg[iSOP], nPos); } assert_nc( iSOP==pSeg->iLeafOffset ); - iNextOff = pSeg->iLeafOffset + pSeg->nPos; + iNextOff = iSOP + pSeg->nPos; } } @@ -252609,31 +255451,31 @@ static void fts5DoSecureDelete( ** is another term following it on this page. So the subsequent term ** needs to be moved to replace the term associated with the entry ** being removed. */ - int nPrefix = 0; - int nSuffix = 0; - int nPrefix2 = 0; - int nSuffix2 = 0; + u64 nPrefix = 0; + u64 nSuffix = 0; + u64 nPrefix2 = 0; + u64 nSuffix2 = 0; iDelKeyOff = iNextOff; - iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2); - iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2); + iNextOff += fts5GetVarint(&aPg[iNextOff], &nPrefix2); + iNextOff += fts5GetVarint(&aPg[iNextOff], &nSuffix2); if( iKey!=1 ){ - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix); + iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nPrefix); } - iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix); + iKeyOff += fts5GetVarint(&aPg[iKeyOff], &nSuffix); nPrefix = MIN(nPrefix, nPrefix2); nSuffix = (nPrefix2 + nSuffix2) - nPrefix; - if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){ + if( (iKeyOff+nSuffix)>(u64)iPgIdx || (iNextOff+nSuffix2)>(u64)iPgIdx ){ FTS5_CORRUPT_IDX(p); }else{ if( iKey!=1 ){ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix); } iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix); - if( nPrefix2>pSeg->term.n ){ + if( nPrefix2>(u64)pSeg->term.n ){ FTS5_CORRUPT_IDX(p); }else if( nPrefix2>nPrefix ){ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix); @@ -252664,7 +255506,7 @@ static void fts5DoSecureDelete( u8 *aTermIdx = &pTerm->p[pTerm->szLeaf]; int nTermIdx = pTerm->nn - pTerm->szLeaf; int iTermIdx = 0; - int iTermOff = 0; + i64 iTermOff = 0; while( 1 ){ u32 iVal = 0; @@ -252675,12 +255517,15 @@ static void fts5DoSecureDelete( } nTermIdx = iTermIdx; - memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); - fts5PutU16(&pTerm->p[2], iTermOff); - - fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); - if( nTermIdx==0 ){ - fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); + if( iTermOff>pTerm->szLeaf ){ + FTS5_CORRUPT_IDX(p); + }else{ + memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx); + fts5PutU16(&pTerm->p[2], iTermOff); + fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx); + if( nTermIdx==0 ){ + fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno); + } } } fts5DataRelease(pTerm); @@ -252703,7 +255548,9 @@ static void fts5DoSecureDelete( int iPrevKeyOut = 0; int iKeyIn = 0; - memmove(&aPg[iOff], &aPg[iNextOff], nMove); + if( nMove>0 ){ + memmove(&aPg[iOff], &aPg[iNextOff], nMove); + } iPgIdx -= nShift; nPg = iPgIdx; fts5PutU16(&aPg[2], iPgIdx); @@ -253623,16 +256470,16 @@ struct Fts5TokenDataMap { ** aMap[] variables. */ struct Fts5TokenDataIter { - int nMapAlloc; /* Allocated size of aMap[] in entries */ - int nMap; /* Number of valid entries in aMap[] */ + i64 nMapAlloc; /* Allocated size of aMap[] in entries */ + i64 nMap; /* Number of valid entries in aMap[] */ Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */ /* The following are used for prefix-queries only. */ Fts5Buffer terms; /* The following are used for other full-token tokendata queries only. */ - int nIter; - int nIterAlloc; + i64 nIter; + i64 nIterAlloc; Fts5PoslistReader *aPoslistReader; int *aPoslistToIter; Fts5Iter *apIter[FLEXARRAY]; @@ -253688,11 +256535,11 @@ static void fts5TokendataIterAppendMap( ){ if( p->rc==SQLITE_OK ){ if( pT->nMap==pT->nMapAlloc ){ - int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; - int nAlloc = nNew * sizeof(Fts5TokenDataMap); + i64 nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64; + i64 nAlloc = nNew * sizeof(Fts5TokenDataMap); Fts5TokenDataMap *aNew; - aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc); + aNew = (Fts5TokenDataMap*)sqlite3_realloc64(pT->aMap, nAlloc); if( aNew==0 ){ p->rc = SQLITE_NOMEM; return; @@ -253718,7 +256565,7 @@ static void fts5TokendataIterAppendMap( */ static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){ Fts5TokenDataMap *aTmp = 0; - int nByte = pT->nMap * sizeof(Fts5TokenDataMap); + i64 nByte = pT->nMap * sizeof(Fts5TokenDataMap); aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte); if( aTmp ){ @@ -254252,9 +257099,10 @@ static Fts5TokenDataIter *fts5AppendTokendataIter( if( p->rc==SQLITE_OK ){ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){ - int nAlloc = pIn ? pIn->nIterAlloc*2 : 16; - int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); - Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte); + i64 nAlloc = pIn ? pIn->nIterAlloc*2 : 16; + i64 nByte = SZ_FTS5TOKENDATAITER(nAlloc+1); + Fts5TokenDataIter *pNew; + pNew = (Fts5TokenDataIter*)sqlite3_realloc64(pIn, nByte); if( pNew==0 ){ p->rc = SQLITE_NOMEM; @@ -254351,8 +257199,8 @@ static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){ /* Ensure the token-mapping is large enough */ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){ - int nNew = (pT->nMapAlloc + nByte) * 2; - Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc( + i64 nNew = (pT->nMapAlloc + nByte) * 2; + Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc64( pT->aMap, nNew*sizeof(Fts5TokenDataMap) ); if( aNew==0 ){ @@ -257267,7 +260115,7 @@ static void fts5SetEstimatedRows(sqlite3_index_info *pIdxInfo, i64 nRow){ if( sqlite3_libversion_number()>=3008002 ) #endif { - pIdxInfo->estimatedRows = nRow; + pIdxInfo->estimatedRows = MAX(1, nRow); } #endif } @@ -257336,19 +260184,30 @@ static int fts5UsePatternMatch( ** a) If a MATCH operator is present, the cost depends on the other ** constraints also present. As follows: ** -** * No other constraints: cost=1000.0 -** * One rowid range constraint: cost=750.0 -** * Both rowid range constraints: cost=500.0 -** * An == rowid constraint: cost=100.0 +** * No other constraints: cost=50000.0 +** * One rowid range constraint: cost=37500.0 +** * Both rowid range constraints: cost=30000.0 +** * An == rowid constraint: cost=25000.0 ** ** b) Otherwise, if there is no MATCH: ** -** * No other constraints: cost=1000000.0 -** * One rowid range constraint: cost=750000.0 -** * Both rowid range constraints: cost=250000.0 -** * An == rowid constraint: cost=10.0 +** * No other constraints: cost=3000000.0 +** * One rowid range constraints: cost=2250000.0 +** * Both rowid range constraint: cost=750000.0 +** * An == rowid constraint: cost=25.0 ** ** Costs are not modified by the ORDER BY clause. +** +** The ratios used in case (a) are based on informal results obtained from +** the tool/fts5cost.tcl script. The "MATCH and ==" combination has the +** cost set quite high because the query may be a prefix query. Unless +** there is a prefix index, prefix queries with rowid constraints are much +** more expensive than non-prefix queries with rowid constraints. +** +** The estimated rows returned is set to the cost/40. For simple queries, +** experimental results show that cost/4 might be about right. But for +** more complex queries that use multiple terms the number of rows might +** be far fewer than this. So we compromise and use cost/40. */ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ Fts5Table *pTab = (Fts5Table*)pVTab; @@ -257381,7 +260240,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ return SQLITE_ERROR; } - idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1); + idxStr = (char*)sqlite3_malloc64((i64)pInfo->nConstraint * 8 + 1); if( idxStr==0 ) return SQLITE_NOMEM; pInfo->idxStr = idxStr; pInfo->needToFreeIdxStr = 1; @@ -257474,21 +260333,35 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ /* Calculate the estimated cost based on the flags set in idxFlags. */ if( bSeenEq ){ - pInfo->estimatedCost = nSeenMatch ? 1000.0 : 25.0; - fts5SetUniqueFlag(pInfo); + pInfo->estimatedCost = nSeenMatch ? 25000.0 : 25.0; fts5SetEstimatedRows(pInfo, 1); + fts5SetUniqueFlag(pInfo); }else{ - if( bSeenLt && bSeenGt ){ - pInfo->estimatedCost = nSeenMatch ? 5000.0 : 750000.0; - }else if( bSeenLt || bSeenGt ){ - pInfo->estimatedCost = nSeenMatch ? 7500.0 : 2250000.0; + i64 nEstRows; + if( nSeenMatch ){ + if( bSeenLt && bSeenGt ){ + pInfo->estimatedCost = 50000.0; + }else if( bSeenLt || bSeenGt ){ + pInfo->estimatedCost = 37500.0; + }else{ + pInfo->estimatedCost = 50000.0; + } + nEstRows = (i64)(pInfo->estimatedCost / 40.0); + for(i=1; iestimatedCost *= 2.5; + nEstRows = nEstRows / 2; + } }else{ - pInfo->estimatedCost = nSeenMatch ? 10000.0 : 3000000.0; + if( bSeenLt && bSeenGt ){ + pInfo->estimatedCost = 750000.0; + }else if( bSeenLt || bSeenGt ){ + pInfo->estimatedCost = 2250000.0; + }else{ + pInfo->estimatedCost = 3000000.0; + } + nEstRows = (i64)(pInfo->estimatedCost / 4.0); } - for(i=1; iestimatedCost *= 0.4; - } - fts5SetEstimatedRows(pInfo, (i64)(pInfo->estimatedCost / 4.0)); + fts5SetEstimatedRows(pInfo, nEstRows); } pInfo->idxNum = idxFlags; @@ -258831,6 +261704,7 @@ static int fts5UpdateMethod( } update_out: + sqlite3Fts5IndexCloseReader(pTab->p.pIndex); pTab->p.pConfig->pzErrmsg = 0; return rc; } @@ -260348,7 +263222,7 @@ static void fts5SourceIdFunc( ){ assert( nArg==0 ); UNUSED_PARAM2(nArg, apUnused); - sqlite3_result_text(pCtx, "fts5: 2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075", -1, SQLITE_TRANSIENT); + sqlite3_result_text(pCtx, "fts5: 2026-04-09 11:41:38 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b", -1, SQLITE_TRANSIENT); } /* @@ -260512,7 +263386,7 @@ static int fts5Init(sqlite3 *db){ int rc; Fts5Global *pGlobal = 0; - pGlobal = (Fts5Global*)sqlite3_malloc(sizeof(Fts5Global)); + pGlobal = (Fts5Global*)sqlite3_malloc64(sizeof(Fts5Global)); if( pGlobal==0 ){ rc = SQLITE_NOMEM; }else{ @@ -262228,7 +265102,7 @@ static int fts5AsciiCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = sqlite3_malloc(sizeof(AsciiTokenizer)); + p = sqlite3_malloc64(sizeof(AsciiTokenizer)); if( p==0 ){ rc = SQLITE_NOMEM; }else{ @@ -262523,7 +265397,7 @@ static int fts5UnicodeCreate( if( nArg%2 ){ rc = SQLITE_ERROR; }else{ - p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer)); + p = (Unicode61Tokenizer*)sqlite3_malloc64(sizeof(Unicode61Tokenizer)); if( p ){ const char *zCat = "L* N* Co"; int i; @@ -262746,7 +265620,7 @@ static int fts5PorterCreate( zBase = azArg[0]; } - pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); + pRet = (PorterTokenizer*)sqlite3_malloc64(sizeof(PorterTokenizer)); if( pRet ){ memset(pRet, 0, sizeof(PorterTokenizer)); rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); @@ -263453,7 +266327,7 @@ static int fts5TriCreate( rc = SQLITE_ERROR; }else{ int i; - pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); + pNew = (TrigramTokenizer*)sqlite3_malloc64(sizeof(*pNew)); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ @@ -265439,7 +268313,7 @@ static int fts5VocabFilterMethod( const char *zCopy = (const char *)sqlite3_value_text(pLe); if( zCopy==0 ) zCopy = ""; pCsr->nLeTerm = sqlite3_value_bytes(pLe); - pCsr->zLeTerm = sqlite3_malloc(pCsr->nLeTerm+1); + pCsr->zLeTerm = sqlite3_malloc64((i64)pCsr->nLeTerm+1); if( pCsr->zLeTerm==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.h b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.h index 6e975a6d19..5d7f82b659 100644 --- a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.h +++ b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/sqlite3.h @@ -146,12 +146,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.51.2" -#define SQLITE_VERSION_NUMBER 3051002 -#define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075" -#define SQLITE_SCM_BRANCH "branch-3.51" -#define SQLITE_SCM_TAGS "release version-3.51.2" -#define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z" +#define SQLITE_VERSION "3.53.0" +#define SQLITE_VERSION_NUMBER 3053000 +#define SQLITE_SOURCE_ID "2026-04-09 11:41:38 4525003a53a7fc63ca75c59b22c79608659ca12f0131f52c18637f829977f20b" +#define SQLITE_SCM_BRANCH "trunk" +#define SQLITE_SCM_TAGS "release major-release version-3.53.0" +#define SQLITE_SCM_DATETIME "2026-04-09T11:41:38.498Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -578,7 +578,7 @@ SQLITE_API int sqlite3_exec( #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8)) #define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8)) -#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */ +#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal only */ /* ** CAPI3REF: Flags For File Open Operations @@ -1290,6 +1290,12 @@ struct sqlite3_io_methods { #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO +/* reserved file-control numbers: +** 101 +** 102 +** 103 +*/ + /* ** CAPI3REF: Mutex Handle @@ -1490,7 +1496,7 @@ typedef const char *sqlite3_filename; ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** -** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces +** ^The xSetSystemCall(), xGetSystemCall(), and xNextSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can @@ -1711,7 +1717,8 @@ SQLITE_API int sqlite3_os_end(void); ** are called "anytime configuration options". ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] with a first argument that is not an anytime -** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE. +** configuration option, then the sqlite3_config() call will +** return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** @@ -2277,9 +2284,10 @@ struct sqlite3_mem_methods { ** is less than 8. The "sz" argument should be a multiple of 8 less than ** 65536. If "sz" does not meet this constraint, it is reduced in size until ** it does. -**
  • The third argument ("cnt") is the number of slots. Lookaside is disabled -** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so -** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" +**

  • The third argument ("cnt") is the number of slots. +** Lookaside is disabled if "cnt"is less than 1. +* The "cnt" value will be reduced, if necessary, so +** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt" ** parameter is usually chosen so that the product of "sz" and "cnt" is less ** than 1,000,000. ** @@ -2567,12 +2575,15 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]] **

    SQLITE_DBCONFIG_STMT_SCANSTATUS
    **
    The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in -** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears -** a flag that enables collection of the sqlite3_stmt_scanstatus_v2() -** statistics. For statistics to be collected, the flag must be set on -** the database handle both when the SQL statement is prepared and when it -** is stepped. The flag is set (collection of statistics is enabled) -** by default.

    This option takes two arguments: an integer and a pointer to +** [SQLITE_ENABLE_STMT_SCANSTATUS] builds. In this case, it sets or clears +** a flag that enables collection of run-time performance statistics +** used by [sqlite3_stmt_scanstatus_v2()] and the [nexec and ncycle] +** columns of the [bytecode virtual table]. +** For statistics to be collected, the flag must be set on +** the database handle both when the SQL statement is +** [sqlite3_prepare|prepared] and when it is [sqlite3_step|stepped]. +** The flag is set (collection of statistics is enabled) by default. +**

    This option takes two arguments: an integer and a pointer to ** an integer. The first argument is 1, 0, or -1 to enable, disable, or ** leave unchanged the statement scanstatus option. If the second argument ** is not NULL, then the value of the statement scanstatus setting after @@ -2645,16 +2656,34 @@ struct sqlite3_mem_methods { ** comments are allowed in SQL text after processing the first argument. **

    ** +** [[SQLITE_DBCONFIG_FP_DIGITS]] +**
    SQLITE_DBCONFIG_FP_DIGITS
    +**
    The SQLITE_DBCONFIG_FP_DIGITS setting is a small integer that determines +** the number of significant digits that SQLite will attempt to preserve when +** converting floating point numbers (IEEE 754 "doubles") into text. The +** default value 17, as of SQLite version 3.52.0. The value was 15 in all +** prior versions.

    +** This option takes two arguments which are an integer and a pointer +** to an integer. The first argument is a small integer, between 3 and 23, or +** zero. The FP_DIGITS setting is changed to that small integer, or left +** unaltered if the first argument is zero or out of range. The second argument +** is a pointer to an integer. If the pointer is not NULL, then the value of +** the FP_DIGITS setting, after possibly being modified by the first +** arguments, is written into the integer to which the second argument points. +**

    +** ** ** ** [[DBCONFIG arguments]]

    Arguments To SQLITE_DBCONFIG Options

    ** **

    Most of the SQLITE_DBCONFIG options take two arguments, so that the ** overall call to [sqlite3_db_config()] has a total of four parameters. -** The first argument (the third parameter to sqlite3_db_config()) is an integer. -** The second argument is a pointer to an integer. If the first argument is 1, -** then the option becomes enabled. If the first integer argument is 0, then the -** option is disabled. If the first argument is -1, then the option setting +** The first argument (the third parameter to sqlite3_db_config()) is +** an integer. +** The second argument is a pointer to an integer. If the first argument is 1, +** then the option becomes enabled. If the first integer argument is 0, +** then the option is disabled. +** If the first argument is -1, then the option setting ** is unchanged. The second argument, the pointer to an integer, may be NULL. ** If the second argument is not NULL, then a value of 0 or 1 is written into ** the integer to which the second argument points, depending on whether the @@ -2662,9 +2691,10 @@ struct sqlite3_mem_methods { ** the first argument. ** **

    While most SQLITE_DBCONFIG options use the argument format -** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME] -** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the -** documentation of those exceptional options for details. +** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME], +** [SQLITE_DBCONFIG_LOOKASIDE], and [SQLITE_DBCONFIG_FP_DIGITS] options +** are different. See the documentation of those exceptional options for +** details. */ #define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ @@ -2689,7 +2719,8 @@ struct sqlite3_mem_methods { #define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */ -#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */ +#define SQLITE_DBCONFIG_FP_DIGITS 1023 /* int int* */ +#define SQLITE_DBCONFIG_MAX 1023 /* Largest DBCONFIG */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes @@ -4171,6 +4202,7 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename); **

  • sqlite3_errmsg() **
  • sqlite3_errmsg16() **
  • sqlite3_error_offset() +**
  • sqlite3_db_handle() ** ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language @@ -4217,7 +4249,7 @@ SQLITE_API const char *sqlite3_errstr(int); SQLITE_API int sqlite3_error_offset(sqlite3 *db); /* -** CAPI3REF: Set Error Codes And Message +** CAPI3REF: Set Error Code And Message ** METHOD: sqlite3 ** ** Set the error code of the database handle passed as the first argument @@ -4336,6 +4368,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
    SQLITE_LIMIT_EXPR_DEPTH
    **
    The maximum depth of the parse tree on any expression.
    )^ ** +** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
    SQLITE_LIMIT_PARSER_DEPTH
    +**
    The maximum depth of the LALR(1) parser stack used to analyze +** input SQL statements.
    )^ +** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
    SQLITE_LIMIT_COMPOUND_SELECT
    **
    The maximum number of terms in a compound SELECT statement.
    )^ ** @@ -4380,6 +4416,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_WORKER_THREADS 11 +#define SQLITE_LIMIT_PARSER_DEPTH 12 /* ** CAPI3REF: Prepare Flags @@ -4424,12 +4461,29 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** fails, the sqlite3_prepare_v3() call returns the same error indications ** with or without this flag; it just omits the call to [sqlite3_log()] that ** logs the error. +** +** [[SQLITE_PREPARE_FROM_DDL]]
    SQLITE_PREPARE_FROM_DDL
    +**
    The SQLITE_PREPARE_FROM_DDL flag causes the SQL compiler to enforce +** security constraints that would otherwise only be enforced when parsing +** the database schema. In other words, the SQLITE_PREPARE_FROM_DDL flag +** causes the SQL compiler to treat the SQL statement being prepared as if +** it had come from an attacker. When SQLITE_PREPARE_FROM_DDL is used and +** [SQLITE_DBCONFIG_TRUSTED_SCHEMA] is off, SQL functions may only be called +** if they are tagged with [SQLITE_INNOCUOUS] and virtual tables may only +** be used if they are tagged with [SQLITE_VTAB_INNOCUOUS]. Best practice +** is to use the SQLITE_PREPARE_FROM_DDL option when preparing any SQL that +** is derived from parts of the database schema. In particular, virtual +** table implementations that run SQL statements that are derived from +** arguments to their CREATE VIRTUAL TABLE statement should always use +** [sqlite3_prepare_v3()] and set the SQLITE_PREPARE_FROM_DDL flag to +** prevent bypass of the [SQLITE_DBCONFIG_TRUSTED_SCHEMA] security checks. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 #define SQLITE_PREPARE_NORMALIZE 0x02 #define SQLITE_PREPARE_NO_VTAB 0x04 #define SQLITE_PREPARE_DONT_LOG 0x10 +#define SQLITE_PREPARE_FROM_DDL 0x20 /* ** CAPI3REF: Compiling An SQL Statement @@ -4443,8 +4497,9 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** ** The preferred routine to use is [sqlite3_prepare_v2()]. The ** [sqlite3_prepare()] interface is legacy and should be avoided. -** [sqlite3_prepare_v3()] has an extra "prepFlags" option that is used -** for special purposes. +** [sqlite3_prepare_v3()] has an extra +** [SQLITE_PREPARE_FROM_DDL|"prepFlags" option] that is sometimes +** needed for special purpose or to pass along security restrictions. ** ** The use of the UTF-8 interfaces is preferred, as SQLite currently ** does all parsing using UTF-8. The UTF-16 interfaces are provided @@ -4849,8 +4904,8 @@ typedef struct sqlite3_context sqlite3_context; ** it should be a pointer to well-formed UTF16 text. ** ^If the third parameter to sqlite3_bind_text64() is not NULL, then ** it should be a pointer to a well-formed unicode string that is -** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16 -** otherwise. +** either UTF8 if the sixth parameter is SQLITE_UTF8 or SQLITE_UTF8_ZT, +** or UTF16 otherwise. ** ** [[byte-order determination rules]] ^The byte-order of ** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF) @@ -4896,10 +4951,15 @@ typedef struct sqlite3_context sqlite3_context; ** object and pointer to it must remain valid until then. ^SQLite will then ** manage the lifetime of its private copy. ** -** ^The sixth argument to sqlite3_bind_text64() must be one of -** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE] -** to specify the encoding of the text in the third parameter. If -** the sixth argument to sqlite3_bind_text64() is not one of the +** ^The sixth argument (the E argument) +** to sqlite3_bind_text64(S,K,Z,N,D,E) must be one of +** [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE] to specify the encoding of the text in the +** third parameter, Z. The special value [SQLITE_UTF8_ZT] means that the +** string argument is both UTF-8 encoded and is zero-terminated. In other +** words, SQLITE_UTF8_ZT means that the Z array is allocated to hold at +** least N+1 bytes and that the Z[N] byte is zero. If +** the E argument to sqlite3_bind_text64(S,K,Z,N,D,E) is not one of the ** allowed values shown above, or if the text encoding is different ** from the encoding specified by the sixth parameter, then the behavior ** is undefined. @@ -5766,6 +5826,52 @@ SQLITE_API int sqlite3_create_window_function( ** ** These constants define integer codes that represent the various ** text encodings supported by SQLite. +** +**
    +** [[SQLITE_UTF8]]
    SQLITE_UTF8
    Text is encoding as UTF-8
    +** +** [[SQLITE_UTF16LE]]
    SQLITE_UTF16LE
    Text is encoding as UTF-16 +** with each code point being expressed "little endian" - the least significant +** byte first. This is the usual encoding, for example on Windows.
    +** +** [[SQLITE_UTF16BE]]
    SQLITE_UTF16BE
    Text is encoding as UTF-16 +** with each code point being expressed "big endian" - the most significant +** byte first. This encoding is less common, but is still sometimes seen, +** specially on older systems. +** +** [[SQLITE_UTF16]]
    SQLITE_UTF16
    Text is encoding as UTF-16 +** with each code point being expressed either little endian or as big +** endian, according to the native endianness of the host computer. +** +** [[SQLITE_ANY]]
    SQLITE_ANY
    This encoding value may only be used +** to declare the preferred text for [application-defined SQL functions] +** created using [sqlite3_create_function()] and similar. If the preferred +** encoding (the 4th parameter to sqlite3_create_function() - the eTextRep +** parameter) is SQLITE_ANY, that indicates that the function does not have +** a preference regarding the text encoding of its parameters and can take +** any text encoding that the SQLite core find convenient to supply. This +** option is deprecated. Please do not use it in new applications. +** +** [[SQLITE_UTF16_ALIGNED]]
    SQLITE_UTF16_ALIGNED
    This encoding +** value may be used as the 3rd parameter (the eTextRep parameter) to +** [sqlite3_create_collation()] and similar. This encoding value means +** that the application-defined collating sequence created expects its +** input strings to be in UTF16 in native byte order, and that the start +** of the strings must be aligned to a 2-byte boundary. +** +** [[SQLITE_UTF8_ZT]]
    SQLITE_UTF8_ZT
    This option can only be +** used to specify the text encoding to strings input to +** [sqlite3_result_text64()] and [sqlite3_bind_text64()]. +** The SQLITE_UTF8_ZT encoding means that the input string (call it "z") +** is UTF-8 encoded and that it is zero-terminated. If the length parameter +** (call it "n") is non-negative, this encoding option means that the caller +** guarantees that z array contains at least n+1 bytes and that the z[n] +** byte has a value of zero. +** This option gives the same output as SQLITE_UTF8, but can be more efficient +** by avoiding the need to make a copy of the input string, in some cases. +** However, if z is allocated to hold fewer than n+1 bytes or if the +** z[n] byte is not zero, undefined behavior may result. +**
    */ #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ @@ -5773,6 +5879,7 @@ SQLITE_API int sqlite3_create_window_function( #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* Deprecated */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ +#define SQLITE_UTF8_ZT 16 /* Zero-terminated UTF8 */ /* ** CAPI3REF: Function Flags @@ -6007,26 +6114,22 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6 ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only -** fail if an out-of-memory error occurs during a format conversion. -** Only the following subset of interfaces are subject to out-of-memory -** errors: -** -**
      -**
    • sqlite3_value_blob() -**
    • sqlite3_value_text() -**
    • sqlite3_value_text16() -**
    • sqlite3_value_text16le() -**
    • sqlite3_value_text16be() -**
    • sqlite3_value_bytes() -**
    • sqlite3_value_bytes16() -**
    -** +** fail if an out-of-memory error occurs while trying to do a +** UTF8→UTF16 or UTF16→UTF8 conversion. ** If an out-of-memory error occurs, then the return value from these ** routines is the same as if the column had contained an SQL NULL value. -** Valid SQL NULL returns can be distinguished from out-of-memory errors -** by invoking the [sqlite3_errcode()] immediately after the suspect +** If the input sqlite3_value was not obtained from [sqlite3_value_dup()], +** then valid SQL NULL returns can also be distinguished from +** out-of-memory errors after extracting the value +** by invoking the [sqlite3_errcode()] immediately after the suspicious ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. +** If the input sqlite3_value was obtained from sqlite3_value_dup() then +** it is disconnected from the database connection and so sqlite3_errcode() +** will not work. +** In that case, the only way to distinguish an out-of-memory +** condition from a true SQL NULL is to invoke sqlite3_value_type() on the +** input to see if it is NULL prior to trying to extract the value. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); @@ -6053,7 +6156,8 @@ SQLITE_API int sqlite3_value_frombind(sqlite3_value*); ** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X) ** returns something other than SQLITE_TEXT, then the return value from ** sqlite3_value_encoding(X) is meaningless. ^Calls to -** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)], +** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], +** [sqlite3_value_text16be(X)], ** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or ** [sqlite3_value_bytes16(X)] might change the encoding of the value X and ** thus change the return from subsequent calls to sqlite3_value_encoding(X). @@ -6184,17 +6288,17 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); ** query execution, under some circumstances the associated auxiliary data ** might be preserved. An example of where this might be useful is in a ** regular-expression matching function. The compiled version of the regular -** expression can be stored as auxiliary data associated with the pattern string. -** Then as long as the pattern string remains the same, +** expression can be stored as auxiliary data associated with the pattern +** string. Then as long as the pattern string remains the same, ** the compiled regular expression can be reused on multiple ** invocations of the same function. ** -** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data -** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument -** value to the application-defined function. ^N is zero for the left-most -** function argument. ^If there is no auxiliary data -** associated with the function argument, the sqlite3_get_auxdata(C,N) interface -** returns a NULL pointer. +** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary +** data associated by the sqlite3_set_auxdata(C,N,P,X) function with the +** Nth argument value to the application-defined function. ^N is zero +** for the left-most function argument. ^If there is no auxiliary data +** associated with the function argument, the sqlite3_get_auxdata(C,N) +** interface returns a NULL pointer. ** ** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the ** N-th argument of the application-defined function. ^Subsequent @@ -6278,10 +6382,14 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi ** ** There is no limit (other than available memory) on the number of different ** client data pointers (with different names) that can be attached to a -** single database connection. However, the implementation is optimized -** for the case of having only one or two different client data names. -** Applications and wrapper libraries are discouraged from using more than -** one client data name each. +** single database connection. However, the current implementation stores +** the content on a linked list. Insert and retrieval performance will +** be proportional to the number of entries. The design use case, and +** the use case for which the implementation is optimized, is +** that an application will store only small number of client data names, +** typically just one or two. This interface is not intended to be a +** generalized key/value store for thousands or millions of keys. It +** will work for that, but performance might be disappointing. ** ** There is no way to enumerate the client data pointers ** associated with a database connection. The N parameter can be thought @@ -6389,10 +6497,14 @@ typedef void (*sqlite3_destructor_type)(void*); ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. -** ^The sqlite3_result_text64() interface sets the return value of an +** ^The sqlite3_result_text64(C,Z,N,D,E) interface sets the return value of an ** application-defined function to be a text string in an encoding -** specified by the fifth (and last) parameter, which must be one -** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. +** specified the E parameter, which must be one +** of [SQLITE_UTF8], [SQLITE_UTF8_ZT], [SQLITE_UTF16], [SQLITE_UTF16BE], +** or [SQLITE_UTF16LE]. ^The special value [SQLITE_UTF8_ZT] means that +** the result text is both UTF-8 and zero-terminated. In other words, +** SQLITE_UTF8_ZT means that the Z array holds at least N+1 bytes and that +** the Z[N] is zero. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces @@ -6479,7 +6591,7 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); -SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, +SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char *z, sqlite3_uint64 n, void(*)(void*), unsigned char encoding); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); @@ -7418,7 +7530,7 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The sqlite3_load_extension() interface attempts to load an ** [SQLite extension] library contained in the file zFile. If ** the file cannot be loaded directly, attempts are made to load -** with various operating-system specific extensions added. +** with various operating-system specific filename extensions added. ** So for example, if "samplelib" cannot be loaded, then names like ** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might ** be tried also. @@ -7426,10 +7538,10 @@ SQLITE_API int sqlite3_table_column_metadata( ** ^The entry point is zProc. ** ^(zProc may be 0, in which case SQLite will try to come up with an ** entry point name on its own. It first tries "sqlite3_extension_init". -** If that does not work, it constructs a name "sqlite3_X_init" where -** X consists of the lower-case equivalent of all ASCII alphabetic -** characters in the filename from the last "/" to the first following -** "." and omitting any initial "lib".)^ +** If that does not work, it tries names of the form "sqlite3_X_init" +** where X consists of the lower-case equivalent of all ASCII alphabetic +** characters or all ASCII alphanumeric characters in the filename from +** the last "/" to the first following "." and omitting any initial "lib".)^ ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the @@ -7503,7 +7615,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); **
     **    int xEntryPoint(
     **      sqlite3 *db,
    -**      const char **pzErrMsg,
    +**      char **pzErrMsg,
     **      const struct sqlite3_api_routines *pThunk
     **    );
     ** 
    )^ @@ -8253,13 +8365,6 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); ** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix ** and Windows. ** -** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor -** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex -** implementation is included with the library. In this case the -** application must supply a custom mutex implementation using the -** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function -** before calling sqlite3_initialize() or any other public sqlite3_ -** function that calls sqlite3_initialize(). ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc() @@ -8614,6 +8719,7 @@ SQLITE_API int sqlite3_test_control(int op, ...); #define SQLITE_TESTCTRL_TUNE 32 #define SQLITE_TESTCTRL_LOGEST 33 #define SQLITE_TESTCTRL_USELONGDOUBLE 34 /* NOT USED */ +#define SQLITE_TESTCTRL_ATOF 34 #define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */ /* @@ -8722,17 +8828,22 @@ SQLITE_API sqlite3_str *sqlite3_str_new(sqlite3*); ** pass the returned value to [sqlite3_free()] to avoid a memory leak. ** ^The [sqlite3_str_finish(X)] interface may return a NULL pointer if any ** errors were encountered during construction of the string. ^The -** [sqlite3_str_finish(X)] interface will also return a NULL pointer if the +** [sqlite3_str_finish(X)] interface might also return a NULL pointer if the ** string in [sqlite3_str] object X is zero bytes long. +** +** ^The [sqlite3_str_free(X)] interface destroys both the sqlite3_str object +** X and the string content it contains. Calling sqlite3_str_free(X) is +** the equivalent of calling [sqlite3_free](sqlite3_str_finish(X)). */ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); +SQLITE_API void sqlite3_str_free(sqlite3_str*); /* ** CAPI3REF: Add Content To A Dynamic String ** METHOD: sqlite3_str ** -** These interfaces add content to an sqlite3_str object previously obtained -** from [sqlite3_str_new()]. +** These interfaces add or remove content to an sqlite3_str object +** previously obtained from [sqlite3_str_new()]. ** ** ^The [sqlite3_str_appendf(X,F,...)] and ** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf] @@ -8755,6 +8866,10 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*); ** ^The [sqlite3_str_reset(X)] method resets the string under construction ** inside [sqlite3_str] object X back to zero bytes in length. ** +** ^The [sqlite3_str_truncate(X,N)] method changes the length of the string +** under construction to be N bytes or less. This routine is a no-op if +** N is negative or if the string is already N bytes or smaller in size. +** ** These methods do not return a result code. ^If an error occurs, that fact ** is recorded in the [sqlite3_str] object and can be recovered by a ** subsequent call to [sqlite3_str_errcode(X)]. @@ -8765,6 +8880,7 @@ SQLITE_API void sqlite3_str_append(sqlite3_str*, const char *zIn, int N); SQLITE_API void sqlite3_str_appendall(sqlite3_str*, const char *zIn); SQLITE_API void sqlite3_str_appendchar(sqlite3_str*, int N, char C); SQLITE_API void sqlite3_str_reset(sqlite3_str*); +SQLITE_API void sqlite3_str_truncate(sqlite3_str*,int N); /* ** CAPI3REF: Status Of A Dynamic String @@ -10295,7 +10411,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** sqlite3_vtab_distinct() return value ** Rows are returned in aOrderBy order -** Rows with the same value in all aOrderBy columns are adjacent +** Rows with the same value in all aOrderBy columns are +** adjacent ** Duplicates over all colUsed columns may be omitted ** 0yesyesno ** 1noyesno @@ -10304,8 +10421,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** ** ** ^For the purposes of comparing virtual table output values to see if the -** values are the same value for sorting purposes, two NULL values are considered -** to be the same. In other words, the comparison operator is "IS" +** values are the same value for sorting purposes, two NULL values are +** considered to be the same. In other words, the comparison operator is "IS" ** (or "IS NOT DISTINCT FROM") and not "==". ** ** If a virtual table implementation is unable to meet the requirements @@ -10598,9 +10715,9 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** a variable pointed to by the "pOut" parameter. ** ** The "flags" parameter must be passed a mask of flags. At present only -** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX +** one flag is defined - [SQLITE_SCANSTAT_COMPLEX]. If SQLITE_SCANSTAT_COMPLEX ** is specified, then status information is available for all elements -** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If +** of a query plan that are reported by "[EXPLAIN QUERY PLAN]" output. If ** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements ** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of ** the EXPLAIN QUERY PLAN output) are available. Invoking API @@ -10614,7 +10731,8 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value ** ** elements used to implement the statement - a non-zero value is returned and ** the variable that pOut points to is unchanged. ** -** See also: [sqlite3_stmt_scanstatus_reset()] +** See also: [sqlite3_stmt_scanstatus_reset()] and the +** [nexec and ncycle] columns of the [bytecode virtual table]. */ SQLITE_API int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ @@ -11156,19 +11274,42 @@ SQLITE_API int sqlite3_deserialize( /* ** CAPI3REF: Bind array values to the CARRAY table-valued function ** -** The sqlite3_carray_bind(S,I,P,N,F,X) interface binds an array value to -** one of the first argument of the [carray() table-valued function]. The -** S parameter is a pointer to the [prepared statement] that uses the carray() -** functions. I is the parameter index to be bound. P is a pointer to the -** array to be bound, and N is the number of eements in the array. The -** F argument is one of constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], -** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], or [SQLITE_CARRAY_BLOB] to -** indicate the datatype of the array being bound. The X argument is not a -** NULL pointer, then SQLite will invoke the function X on the P parameter -** after it has finished using P, even if the call to -** sqlite3_carray_bind() fails. The special-case finalizer -** SQLITE_TRANSIENT has no effect here. +** The sqlite3_carray_bind_v2(S,I,P,N,F,X,D) interface binds an array value to +** parameter that is the first argument of the [carray() table-valued function]. +** The S parameter is a pointer to the [prepared statement] that uses the +** carray() functions. I is the parameter index to be bound. I must be the +** index of the parameter that is the first argument to the carray() +** table-valued function. P is a pointer to the array to be bound, and N +** is the number of elements in the array. The F argument is one of +** constants [SQLITE_CARRAY_INT32], [SQLITE_CARRAY_INT64], +** [SQLITE_CARRAY_DOUBLE], [SQLITE_CARRAY_TEXT], +** or [SQLITE_CARRAY_BLOB] to indicate the datatype of the array P. +** +** If the X argument is not a NULL pointer or one of the special +** values [SQLITE_STATIC] or [SQLITE_TRANSIENT], then SQLite will invoke +** the function X with argument D when it is finished using the data in P. +** The call to X(D) is a destructor for the array P. The destructor X(D) +** is invoked even if the call to sqlite3_carray_bind_v2() fails. If the X +** parameter is the special-case value [SQLITE_STATIC], then SQLite assumes +** that the data static and the destructor is never invoked. If the X +** parameter is the special-case value [SQLITE_TRANSIENT], then +** sqlite3_carray_bind_v2() makes its own private copy of the data prior +** to returning and never invokes the destructor X. +** +** The sqlite3_carray_bind() function works the same as sqlite3_carray_bind_v2() +** with a D parameter set to P. In other words, +** sqlite3_carray_bind(S,I,P,N,F,X) is same as +** sqlite3_carray_bind_v2(S,I,P,N,F,X,P). */ +SQLITE_API int sqlite3_carray_bind_v2( + sqlite3_stmt *pStmt, /* Statement to be bound */ + int i, /* Parameter index */ + void *aData, /* Pointer to array data */ + int nData, /* Number of data elements */ + int mFlags, /* CARRAY flags */ + void (*xDel)(void*), /* Destructor for aData */ + void *pDel /* Optional argument to xDel() */ +); SQLITE_API int sqlite3_carray_bind( sqlite3_stmt *pStmt, /* Statement to be bound */ int i, /* Parameter index */ @@ -13199,6 +13340,232 @@ SQLITE_API int sqlite3session_config(int op, void *pArg); */ #define SQLITE_SESSION_CONFIG_STRMSIZE 1 +/* +** CAPI3REF: Configure a changegroup object +** +** Configure the changegroup object passed as the first argument. +** At present the only valid value for the second parameter is +** [SQLITE_CHANGEGROUP_CONFIG_PATCHSET]. +*/ +SQLITE_API int sqlite3changegroup_config(sqlite3_changegroup*, int, void *pArg); + +/* +** CAPI3REF: Options for sqlite3changegroup_config(). +** +** The following values may be passed as the 2nd parameter to +** sqlite3changegroup_config(). +** +**
    SQLITE_CHANGEGROUP_CONFIG_PATCHSET
    +** A changegroup object generates either a changeset or patchset. Usually, +** this is determined by whether the first call to sqlite3changegroup_add() +** is passed a changeset or a patchset. Or, if the first changes are added +** to the changegroup object using the sqlite3changegroup_change_xxx() +** APIs, then this option may be used to configure whether the changegroup +** object generates a changeset or patchset. +** +** When this option is invoked, parameter pArg must point to a value of +** type int. If the changegroup currently contains zero changes, and the +** value of the int variable is zero or greater than zero, then the +** changegroup is configured to generate a changeset or patchset, +** respectively. It is a no-op, not an error, if the changegroup is not +** configured because it has already started accumulating changes. +** +** Before returning, the int variable is set to 0 if the changegroup is +** configured to generate a changeset, or 1 if it is configured to generate +** a patchset. +*/ +#define SQLITE_CHANGEGROUP_CONFIG_PATCHSET 1 + + +/* +** CAPI3REF: Begin adding a change to a changegroup +** +** This API is used, in concert with other sqlite3changegroup_change_xxx() +** APIs, to add changes to a changegroup object one at a time. To add a +** single change, the caller must: +** +** 1. Invoke sqlite3changegroup_change_begin() to indicate the type of +** change (INSERT, UPDATE or DELETE), the affected table and whether +** or not the change should be marked as indirect. +** +** 2. Invoke sqlite3changegroup_change_int64() or one of the other four +** value functions - _null(), _double(), _text() or _blob() - one or +** more times to specify old.* and new.* values for the change being +** constructed. +** +** 3. Invoke sqlite3changegroup_change_finish() to either finish adding +** the change to the group, or to discard the change altogether. +** +** The first argument to this function must be a pointer to the existing +** changegroup object that the change will be added to. The second argument +** must be SQLITE_INSERT, SQLITE_UPDATE or SQLITE_DELETE. The third is the +** name of the table that the change affects, and the fourth is a boolean +** flag specifying whether the change should be marked as "indirect" (if +** bIndirect is non-zero) or not indirect (if bIndirect is zero). +** +** Following a successful call to this function, this function may not be +** called again on the same changegroup object until after +** sqlite3changegroup_change_finish() has been called. Doing so is an +** SQLITE_MISUSE error. +** +** The changegroup object passed as the first argument must be already +** configured with schema data for the specified table. It may be configured +** either by calling sqlite3changegroup_schema() with a database that contains +** the table, or sqlite3changegroup_add() with a changeset that contains the +** table. If the changegroup object has not been configured with a schema for +** the specified table when this function is called, SQLITE_ERROR is returned. +** +** If successful, SQLITE_OK is returned. Otherwise, if an error occurs, an +** SQLite error code is returned. In this case, if argument pzErr is non-NULL, +** then (*pzErr) may be set to point to a buffer containing a utf-8 formated, +** nul-terminated, English language error message. It is the responsibility +** of the caller to eventually free this buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_begin( + sqlite3_changegroup*, + int eOp, + const char *zTab, + int bIndirect, + char **pzErr +); + +/* +** CAPI3REF: Add a 64-bit integer to a changegroup +** +** This function may only be called between a successful call to +** sqlite3changegroup_change_begin() and its matching +** sqlite3changegroup_change_finish() call. If it is called at any +** other time, it is an SQLITE_MISUSE error. Calling this function +** specifies a 64-bit integer value to be used in the change currently being +** added to the changegroup object passed as the first argument. +** +** The second parameter, bNew, specifies whether the value is to be part of +** the new.* (if bNew is non-zero) or old.* (if bNew is zero) record of +** the change under construction. If this does not match the type of change +** specified by the preceding call to sqlite3changegroup_change_begin() (i.e. +** an old.* value for an SQLITE_INSERT change, or a new.* value for an +** SQLITE_DELETE), then SQLITE_ERROR is returned. +** +** The third parameter specifies the column of the old.* or new.* record that +** the value will be a part of. If the specified table has an explicit primary +** key, then this is the index of the table column, numbered from 0 in the order +** specified within the CREATE TABLE statement. Or, if the table uses an +** implicit rowid key, then the column 0 is the rowid and the explicit columns +** are numbered starting from 1. If the iCol parameter is less than 0 or greater +** than the index of the last column in the table, SQLITE_RANGE is returned. +** +** The fourth parameter is the integer value to use as part of the old.* or +** new.* record. +** +** If this call is successful, SQLITE_OK is returned. Otherwise, if an +** error occurs, an SQLite error code is returned. +*/ +SQLITE_API int sqlite3changegroup_change_int64( + sqlite3_changegroup*, + int bNew, + int iCol, + sqlite3_int64 iVal +); + +/* +** CAPI3REF: Add a NULL to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently under construction with a NULL value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_null(sqlite3_changegroup*, int, int); + +/* +** CAPI3REF: Add an double to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). Except that +** it configures the change currently being constructed with a real value +** instead of a 64-bit integer. +*/ +SQLITE_API int sqlite3changegroup_change_double(sqlite3_changegroup*, int, int, double); + +/* +** CAPI3REF: Add a text value to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a text value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the text encoded using +** utf-8. Parameter nVal may either be the size of the text value in bytes, or +** else a negative value, in which case the buffer pVal points to is assumed to +** be nul-terminated. +*/ +SQLITE_API int sqlite3changegroup_change_text( + sqlite3_changegroup*, int, int, const char *pVal, int nVal +); + +/* +** CAPI3REF: Add a blob to a changegroup +** +** This function is similar to sqlite3changegroup_change_int64(). It configures +** the currently accumulated change with a blob value instead of a 64-bit +** integer. Parameter pVal points to a buffer containing the blob. Parameter +** nVal is the size of the blob in bytes. +*/ +SQLITE_API int sqlite3changegroup_change_blob( + sqlite3_changegroup*, int, int, const void *pVal, int nVal +); + +/* +** CAPI3REF: Finish adding one-at-at-time changes to a changegroup +** +** This function may only be called following a successful call to +** sqlite3changegroup_change_begin(). Otherwise, it is an SQLITE_MISUSE error. +** +** If parameter bDiscard is non-zero, then the current change is simply +** discarded. In this case this function is always successful and SQLITE_OK +** returned. +** +** If parameter bDiscard is zero, then an attempt is made to add the current +** change to the changegroup. Assuming the changegroup is configured to +** produce a changeset (not a patchset), this requires that: +** +** * If the change is an INSERT or DELETE, then a value must be specified +** for all columns of the new.* or old.* record, respectively. +** +** * If the change is an UPDATE record, then values must be provided for +** the PRIMARY KEY columns of the old.* record, but must not be provided +** for PRIMARY KEY columns of the new.* record. +** +** * If the change is an UPDATE record, then for each non-PRIMARY KEY +** column in the old.* record for which a value has been provided, a +** value must also be provided for the same column in the new.* record. +** Similarly, for each non-PK column in the old.* record for which +** a value is not provided, a value must not be provided for the same +** column in the new.* record. +** +** * All values specified for PRIMARY KEY columns must be non-NULL. +** +** Otherwise, it is an error. +** +** If the changegroup already contains a change for the same row (identified +** by PRIMARY KEY columns), then the current change is combined with the +** existing change in the same way as for sqlite3changegroup_add(). +** +** For a patchset, all of the above rules apply except that it doesn't matter +** whether or not values are provided for the non-PK old.* record columns +** for an UPDATE or DELETE change. This means that code used to produce +** a changeset using the sqlite3changegroup_change_xxx() APIs may also +** be used to produce patchsets. +** +** If the call is successful, SQLITE_OK is returned. Otherwise, if an error +** occurs, an SQLite error code is returned. If an error is returned and +** parameter pzErr is not NULL, then (*pzErr) may be set to point to a buffer +** containing a nul-terminated, utf-8 encoded, English language error message. +** It is the responsibility of the caller to eventually free any such error +** message buffer using sqlite3_free(). +*/ +SQLITE_API int sqlite3changegroup_change_finish( + sqlite3_changegroup*, + int bDiscard, + char **pzErr +); + /* ** Make sure we can call this stuff from C++. */ diff --git a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/update_sqlite.sh b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/update_sqlite.sh index 95d0a3241d..f78e5d1c47 100755 --- a/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/update_sqlite.sh +++ b/local/recipes/qt/qtbase/source/src/3rdparty/sqlite/update_sqlite.sh @@ -7,8 +7,8 @@ # sqlite.c and sqlite.h and updates qt_attribution.json version_maj=3 -version_min=51 -version_patch=2 +version_min=53 +version_patch=0 year=2026 version=${version_maj}.${version_min}.${version_patch} diff --git a/local/recipes/qt/qtbase/source/src/android/jar/src/org/qtproject/qt/android/QtEditText.java b/local/recipes/qt/qtbase/source/src/android/jar/src/org/qtproject/qt/android/QtEditText.java index 7977496189..cbc70b8d8c 100644 --- a/local/recipes/qt/qtbase/source/src/android/jar/src/org/qtproject/qt/android/QtEditText.java +++ b/local/recipes/qt/qtbase/source/src/android/jar/src/org/qtproject/qt/android/QtEditText.java @@ -106,7 +106,9 @@ class QtEditText extends View public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = m_inputType; - outAttrs.imeOptions = m_imeOptions; + outAttrs.imeOptions = System.getenv("QT_ANDROID_NO_FULLSCREEN_KEYBOARD") != null + ? m_imeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN + : m_imeOptions; outAttrs.initialCapsMode = m_initialCapsMode; m_inputConnection = new QtInputConnection(this,m_qtInputConnectionListener); diff --git a/local/recipes/qt/qtbase/source/src/android/templates/AndroidManifest.xml b/local/recipes/qt/qtbase/source/src/android/templates/AndroidManifest.xml index 2e6da0a601..66d709f156 100644 --- a/local/recipes/qt/qtbase/source/src/android/templates/AndroidManifest.xml +++ b/local/recipes/qt/qtbase/source/src/android/templates/AndroidManifest.xml @@ -16,7 +16,6 @@ android:hardwareAccelerated="true" android:label="-- %%INSERT_APP_NAME%% --" android:icon="-- %%INSERT_APP_ICON%% --" - android:requestLegacyExternalStorage="true" android:enableOnBackInvokedCallback="false" android:allowBackup="true" android:fullBackupOnly="false"> diff --git a/local/recipes/qt/qtbase/source/src/android/templates/doc/src/android-manifest-file-configuration.qdoc b/local/recipes/qt/qtbase/source/src/android/templates/doc/src/android-manifest-file-configuration.qdoc index cb885c41cd..f197dd8823 100644 --- a/local/recipes/qt/qtbase/source/src/android/templates/doc/src/android-manifest-file-configuration.qdoc +++ b/local/recipes/qt/qtbase/source/src/android/templates/doc/src/android-manifest-file-configuration.qdoc @@ -70,7 +70,7 @@ Qt sets the following manifest configuration by default: default values are \c anyDensity, \c largeScreens, \c normalScreens, and \c smallScreens. \row - \li {1, 7} \l {Android: App Manifest }{} + \li {1, 6} \l {Android: App Manifest }{} \li android:name \li The application class name. Default value is \c {org.qtproject.qt.android.bindings.QtApplication}. @@ -86,9 +86,6 @@ Qt sets the following manifest configuration by default: \row \li android:hardwareAccelerated \li Sets hardware acceleration preference. The default value is \c true. -\row - \li android:requestLegacyExternalStorage - \li Whether to use Android scoped storage. The default value is \c true. \row \li android:allowBackup \li Whether to allow the application to participate in the backup and restore diff --git a/local/recipes/qt/qtbase/source/src/android/templates_cmake/app/AndroidManifest.xml.in b/local/recipes/qt/qtbase/source/src/android/templates_cmake/app/AndroidManifest.xml.in index 61c33cc765..da9b50f4ee 100644 --- a/local/recipes/qt/qtbase/source/src/android/templates_cmake/app/AndroidManifest.xml.in +++ b/local/recipes/qt/qtbase/source/src/android/templates_cmake/app/AndroidManifest.xml.in @@ -18,7 +18,6 @@ android:hardwareAccelerated="true" android:label="@APP_NAME@" @APP_ICON@ - android:requestLegacyExternalStorage="true" android:allowBackup="true" android:fullBackupOnly="false"> diff --git a/local/recipes/qt/qtbase/source/src/corelib/Qt6WasmMacros.cmake b/local/recipes/qt/qtbase/source/src/corelib/Qt6WasmMacros.cmake index 9ab51bf3e7..9df3170d84 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/Qt6WasmMacros.cmake +++ b/local/recipes/qt/qtbase/source/src/corelib/Qt6WasmMacros.cmake @@ -33,6 +33,16 @@ function(_qt_internal_wasm_add_target_helpers target) set(PRELOAD "") endif() + if(DEFINED QT_WASM_SOURCE_MAP_BASE) + set(WASM_SOURCE_MAP_BASE "${QT_WASM_SOURCE_MAP_BASE}") + target_link_options("${target}" + PRIVATE + "-gsource-map" + "--source-map-base" + "${WASM_SOURCE_MAP_BASE}") + + endif() + get_target_property(target_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY) get_target_property(is_test ${target} _qt_is_test_executable) diff --git a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qeventdispatcher_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qeventdispatcher_unix_p.h deleted file mode 100644 index 6596e998c9..0000000000 --- a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qeventdispatcher_unix_p.h +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (C) 2016 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 - -#ifndef QEVENTDISPATCHER_UNIX_P_H -#define QEVENTDISPATCHER_UNIX_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qabstracteventdispatcher.h" -#include "QtCore/qlist.h" -#include "private/qabstracteventdispatcher_p.h" -#include "private/qcore_unix_p.h" -#include "QtCore/qvarlengtharray.h" -#include "QtCore/qhash.h" -#include "private/qtimerinfo_unix_p.h" - -QT_BEGIN_NAMESPACE - -class QEventDispatcherUNIXPrivate; - -struct Q_CORE_EXPORT QSocketNotifierSetUNIX final -{ - inline QSocketNotifierSetUNIX() noexcept; - - inline bool isEmpty() const noexcept; - inline short events() const noexcept; - - QSocketNotifier *notifiers[3]; -}; - -Q_DECLARE_TYPEINFO(QSocketNotifierSetUNIX, Q_PRIMITIVE_TYPE); - -struct QThreadPipe -{ - QThreadPipe(); - ~QThreadPipe(); - - bool init(); - pollfd prepare() const; - - void wakeUp(); - int check(const pollfd &pfd); - - // note for eventfd(7) support: - // fds[0] stores the eventfd, fds[1] is unused - int fds[2] = { -1, -1 }; - QAtomicInt wakeUps; - -#if defined(Q_OS_VXWORKS) - static constexpr int len_name = 20; - char name[len_name] = {}; -#endif -}; - -class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcherV2 -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QEventDispatcherUNIX) - -public: - explicit QEventDispatcherUNIX(QObject *parent = nullptr); - ~QEventDispatcherUNIX(); - - bool processEvents(QEventLoop::ProcessEventsFlags flags) override; - - void registerSocketNotifier(QSocketNotifier *notifier) final; - void unregisterSocketNotifier(QSocketNotifier *notifier) final; - - void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, - QObject *object) override final; - bool unregisterTimer(Qt::TimerId timerId) override final; - bool unregisterTimers(QObject *object) override final; - QList timersForObject(QObject *object) const override final; - Duration remainingTime(Qt::TimerId timerId) const override final; - - void wakeUp() override; - void interrupt() final; - -protected: - QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent = nullptr); -}; - -class Q_CORE_EXPORT QEventDispatcherUNIXPrivate : public QAbstractEventDispatcherPrivate -{ - Q_DECLARE_PUBLIC(QEventDispatcherUNIX) - -public: - QEventDispatcherUNIXPrivate(); - ~QEventDispatcherUNIXPrivate(); - - int activateTimers(); - - void markPendingSocketNotifiers(); - int activateSocketNotifiers(); - void setSocketNotifierPending(QSocketNotifier *notifier); - - QThreadPipe threadPipe; - QList pollfds; - - QHash socketNotifiers; - QList pendingNotifiers; - - QTimerInfoList timerList; - QAtomicInt interrupt; // bool -}; - -inline QSocketNotifierSetUNIX::QSocketNotifierSetUNIX() noexcept -{ - notifiers[0] = nullptr; - notifiers[1] = nullptr; - notifiers[2] = nullptr; -} - -inline bool QSocketNotifierSetUNIX::isEmpty() const noexcept -{ - return !notifiers[0] && !notifiers[1] && !notifiers[2]; -} - -inline short QSocketNotifierSetUNIX::events() const noexcept -{ - short result = 0; - - if (notifiers[0]) - result |= POLLIN; - - if (notifiers[1]) - result |= POLLOUT; - - if (notifiers[2]) - result |= POLLPRI; - - return result; -} - -QT_END_NAMESPACE - -#endif // QEVENTDISPATCHER_UNIX_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qtimerinfo_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qtimerinfo_unix_p.h deleted file mode 100644 index 293e9c4d4e..0000000000 --- a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qtimerinfo_unix_p.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2016 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 - -#ifndef QTIMERINFO_UNIX_P_H -#define QTIMERINFO_UNIX_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include "qabstracteventdispatcher.h" - -#include // struct timespec -#include - -QT_BEGIN_NAMESPACE - -// internal timer info -struct QTimerInfo -{ - using Duration = QAbstractEventDispatcher::Duration; - using TimePoint = std::chrono::time_point; - QTimerInfo(Qt::TimerId timerId, Duration interval, Qt::TimerType type, QObject *obj) - : interval(interval), id(timerId), timerType(type), obj(obj) - { - } - - TimePoint timeout = {}; // - when to actually fire - Duration interval = Duration{-1}; // - timer interval - Qt::TimerId id = Qt::TimerId::Invalid; // - timer identifier - Qt::TimerType timerType; // - timer type - QObject *obj = nullptr; // - object to receive event - QTimerInfo **activateRef = nullptr; // - ref from activateTimers -}; - -class Q_CORE_EXPORT QTimerInfoList -{ -public: - using Duration = QAbstractEventDispatcher::Duration; - using TimerInfo = QAbstractEventDispatcher::TimerInfoV2; - QTimerInfoList(); - - mutable std::chrono::steady_clock::time_point currentTime; - - std::optional timerWait(); - void timerInsert(QTimerInfo *); - - Duration remainingDuration(Qt::TimerId timerId) const; - - void registerTimer(Qt::TimerId timerId, Duration interval, - Qt::TimerType timerType, QObject *object); - bool unregisterTimer(Qt::TimerId timerId); - bool unregisterTimers(QObject *object); - QList registeredTimers(QObject *object) const; - - int activateTimers(); - bool hasPendingTimers(); - - void clearTimers() - { - qDeleteAll(timers); - timers.clear(); - } - - bool isEmpty() const { return timers.empty(); } - - qsizetype size() const { return timers.size(); } - - auto findTimerById(Qt::TimerId timerId) const - { - auto matchesId = [timerId](const auto &t) { return t->id == timerId; }; - return std::find_if(timers.cbegin(), timers.cend(), matchesId); - } - -private: - std::chrono::steady_clock::time_point updateCurrentTime() const; - - // state variables used by activateTimers() - QTimerInfo *firstTimerInfo = nullptr; - QList timers; -}; - -QT_END_NAMESPACE - -#endif // QTIMERINFO_UNIX_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/compat/removed_api.cpp b/local/recipes/qt/qtbase/source/src/corelib/compat/removed_api.cpp index 5bad643ea3..1d0ed9bde0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/compat/removed_api.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/compat/removed_api.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #define QT_CORE_BUILD_REMOVED_API diff --git a/local/recipes/qt/qtbase/source/src/corelib/configure.cmake b/local/recipes/qt/qtbase/source/src/corelib/configure.cmake index 2f6f28f19d..36a2fb7ecb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/configure.cmake +++ b/local/recipes/qt/qtbase/source/src/corelib/configure.cmake @@ -413,6 +413,11 @@ qt_config_compile_test(liburing int main(void) { + io_uring_op op = IORING_OP_NOP; + (void)op; + struct io_uring_params params{}; + io_uring_setup(0, ¶ms); + io_uring_register(0, IORING_REGISTER_EVENTFD, nullptr, 0); io_uring_enter(0, 0, 0, 0, nullptr); return 0; } @@ -584,7 +589,7 @@ qt_config_compile_test(renameat2 int main(int, char **argv) { /* BEGIN TEST: */ -renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_NOREPLACE | RENAME_WHITEOUT); +renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_NOREPLACE); /* END TEST: */ return 0; } @@ -881,7 +886,7 @@ qt_feature("linkat" PRIVATE qt_feature("liburing" PRIVATE LABEL "liburing" AUTODETECT LINUX - CONDITION Liburing_FOUND + CONDITION TEST_liburing AND Liburing_FOUND ) qt_feature("std-atomic64" PUBLIC LABEL "64 bit atomic operations" @@ -968,7 +973,7 @@ qt_feature("qqnx_pps" PRIVATE ) qt_feature("renameat2" PRIVATE LABEL "renameat2()" - CONDITION ( LINUX OR HURD ) AND TEST_renameat2 + CONDITION UNIX AND TEST_renameat2 ) qt_feature("slog2" PRIVATE LABEL "slog2" diff --git a/local/recipes/qt/qtbase/source/src/corelib/doc/snippets/code/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/corelib/doc/snippets/code/CMakeLists.txt index 94be5b6954..b4de6f2e2d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/doc/snippets/code/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/corelib/doc/snippets/code/CMakeLists.txt @@ -41,10 +41,8 @@ add_library(corelib_snippets_code OBJECT src_corelib_kernel_qmath.cpp src_corelib_kernel_qmetaobject.cpp src_corelib_kernel_qmetatype.cpp - src_corelib_kernel_qmimedata.cpp src_corelib_kernel_qproperty.cpp src_corelib_kernel_qvariant.cpp - src_corelib_mimetype_qmimedatabase.cpp src_corelib_plugin_qlibrary.cpp src_corelib_plugin_quuid.cpp src_corelib_serialization_qcborstream.cpp @@ -88,7 +86,6 @@ add_library(corelib_snippets_code OBJECT src_corelib_tools_qsharedpointer.cpp src_corelib_tools_qsize.cpp src_corelib_xml_qxmlstream.cpp - src_gui_itemviews_qidentityproxymodel.cpp src_gui_itemviews_qitemselectionmodel.cpp ) @@ -106,6 +103,14 @@ if(APPLE) ) endif() + +if(QT_FEATURE_mimetype) + target_sources(corelib_snippets_code PRIVATE + src_corelib_kernel_qmimedata.cpp + src_corelib_mimetype_qmimedatabase.cpp + ) +endif() + if(QT_FEATURE_process) target_sources(corelib_snippets_code PRIVATE src_corelib_io_qiodevice.cpp @@ -137,6 +142,11 @@ if(QT_FEATURE_gui) target_link_libraries(corelib_snippets_code PRIVATE Qt::Gui ) + if(QT_FEATURE_identityproxymodel) + target_sources(corelib_snippets_code PRIVATE + src_gui_itemviews_qidentityproxymodel.cpp + ) + endif() endif() if(QT_FEATURE_concurrent) @@ -145,10 +155,14 @@ if(QT_FEATURE_concurrent) ) target_sources(corelib_snippets_code PRIVATE src_corelib_thread_qexception.cpp - src_corelib_thread_qfuture.cpp src_corelib_thread_qfuturesynchronizer.cpp src_corelib_thread_qfuturewatcher.cpp ) + if(QT_FEATURE_network) + target_sources(corelib_snippets_code PRIVATE + src_corelib_thread_qfuture.cpp + ) + endif() endif() if(QT_FEATURE_network) diff --git a/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc index 0a0dc0b3c5..d8cc51e302 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc @@ -378,16 +378,22 @@ The mentioned variables are used internally by \l{androiddeployqt}. \preliminarycmakevariable \cmakevariableandroidonly -This variable enables Java code generation for QML components of the target application. The +Set to \c TRUE to enable Java code generation for QML components of the target application. The generated code will be included in the resulting package. The Java package name of generated classes will be the same as the Android app package. If the leaf part of the package name is not the same as the target executable, an extra static class with the same name as the capitalized target executable will surround all QML modules enclosing Java classes. Each QML -module class, again in a capitalized form, will contain QtQuickViewContent extension classes +module class, again in a capitalized form, will contain \l{QtQuickViewContent} extension classes that represent QML components of that module. -*/ -\sa{androiddeployqt} +\badcode +set(QT_ANDROID_GENERATE_JAVA_QTQUICKVIEW_CONTENTS TRUE) +set_source_files_properties(MyView.qml PROPERTIES QT_QML_GENERATE_ANDROID_JAVA_CLASS TRUE) +qt_add_qml_module(myapp URI MyModule QML_FILES MyView.qml) +\endcode + +\sa {QT_QML_GENERATE_ANDROID_JAVA_CLASS}, {androiddeployqt} +*/ /*! \page cmake-variable-qt-use-target-android-build-dir.html \ingroup cmake-variables-qtcore diff --git a/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/qt_android_add_apk_target.qdoc b/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/qt_android_add_apk_target.qdoc index b2415730f5..eed0966bc3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/qt_android_add_apk_target.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/doc/src/cmake/qt_android_add_apk_target.qdoc @@ -26,20 +26,21 @@ qt_android_add_apk_target(target) \section1 Description -The \c{_make_apk} and \c{_make_aab} custom targets created by -this command take an Android deployment settings file and generate APK and -AAB respectively by running \c{androiddeployqt}. +The \c{_make_apk}, \c{_make_aab}, and \c{_make_aar} +custom targets created by this command take an Android deployment settings file +and generate APK, AAB, and AAR packages respectively by running \c{androiddeployqt}. The location of the settings file is taken from the \c{target}'s \c{QT_ANDROID_DEPLOYMENT_SETTINGS_FILE} property. This file is typically created by \l{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}. The respective Android package will be generated in an \c{android-build} subdirectory below the CMake build directory of the \c{target}. -The \c{_make_apk} and \c{_make_aab} targets will be -automatically added as dependencies of the \c{apk} and \c{aab} build targets -respectively, which will be created automatically. Creating of the \c{apk} and -\c{aab} targets can be disabled by setting the \c{QT_NO_GLOBAL_APK_TARGET} and -\c{QT_NO_GLOBAL_AAB_TARGET} variables to \c{TRUE}. +The \c{_make_apk}, \c{_make_aab}, and \c{_make_aar} +targets will be automatically added as dependencies of the \c{apk}, \c{aab}, +and \c{aar} build targets respectively, which will be created automatically. +Creating of the \c{apk}, \c{aab}, and \c{aar} targets can be disabled by +setting the \c{QT_NO_GLOBAL_APK_TARGET}, \c{QT_NO_GLOBAL_AAB_TARGET}, and +\c{QT_NO_GLOBAL_AAR_TARGET} variables to \c{TRUE}. \sa {qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}, {qt6_finalize_target}{qt_finalize_target()}, @@ -49,7 +50,8 @@ respectively, which will be created automatically. Creating of the \c{apk} and \snippet cmake-macros/examples.cmake qt_android_deploy_basic -The above commands define the \c{myapp_make_apk}, \c{myapp_make_aab}, \c{apk}, -and \c{aab} build targets which can be used to generate just the -\c{myapp} packages or all APKs and AABs in the project respectively. +The above commands define the \c{myapp_make_apk}, \c{myapp_make_aab}, +\c{myapp_make_aar}, \c{apk}, \c{aab}, and \c{aar} build targets which can be +used to generate just the \c{myapp} packages or all APKs, AABs, and AARs in +the project respectively. */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/doc/src/objectmodel/metaobjects.qdoc b/local/recipes/qt/qtbase/source/src/corelib/doc/src/objectmodel/metaobjects.qdoc index 44f574816e..5e8c5acbb4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/doc/src/objectmodel/metaobjects.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/doc/src/objectmodel/metaobjects.qdoc @@ -88,7 +88,7 @@ \snippet qtcast/qtcast.cpp 4 The cast to QLabel, on the other hand, fails. The pointer is then - set to 0. This makes it possible to handle objects of different + set to \nullptr. This makes it possible to handle objects of different types differently at run-time, based on the type: \snippet qtcast/qtcast.cpp 5 diff --git a/local/recipes/qt/qtbase/source/src/corelib/doc/src/timers.qdoc b/local/recipes/qt/qtbase/source/src/corelib/doc/src/timers.qdoc index 5b1cc62510..626ce5f171 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/doc/src/timers.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/doc/src/timers.qdoc @@ -25,12 +25,17 @@ timer event there. For this mechanism to work, the application must run in an event - loop. You cat start an event loop with QApplication::exec(). When a + loop. You can start an event loop with QCoreApplication::exec(). For + \l {Qt Widgets} applications, see QApplication::exec(). When a timer fires, the application sends a QTimerEvent, and the flow of control leaves the event loop until the timer event is processed. This implies that a timer cannot fire while your application is busy doing something else. In other words: the accuracy of timers - depends on the granularity of your application. + depends on the granularity of your application. The accuracy of timers also + depends on the underlying operating system and hardware. Short intervals may + be rounded or delayed by the system scheduler, and all timer types may time + out later than requested if the system is busy. For more information about + timer resolution and Qt::TimerType, see the QTimer documentation. In multithreaded applications, you can use the timer mechanism in any thread that has an event loop. To start an event loop from a @@ -54,10 +59,6 @@ because QTimer's precision couldn't be changed to \c std::chrono::nanoseconds without breaking binary-compatibility. - The accuracy of the timers depends on the underlying operating system. - Windows 2000 has 15ms accuracy; other systems that we have tested can - handle 1ms intervals. - QTimer provides regular timers that emit a signal when the timer fires, and inherits from QObject so that it fits well into the ownership structure of most Qt programs. The normal way of using it is like this: diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/archdetect.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/archdetect.cpp index 0703d1c8e9..89f0c1120a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/archdetect.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/archdetect.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qprocessordetection.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/minimum-linux_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/minimum-linux_p.h index b2c74c5c37..7fc55b5704 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/minimum-linux_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/minimum-linux_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef MINIMUMLINUX_P_H #define MINIMUMLINUX_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q17memory.h b/local/recipes/qt/qtbase/source/src/corelib/global/q17memory.h index ae1c55272f..b922076d19 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q17memory.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q17memory.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef Q17MEMORY_H #define Q17MEMORY_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20algorithm.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20algorithm.h index 24d801b2cd..cd45673a9a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20algorithm.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20algorithm.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20ALGORITHM_H #define Q20ALGORITHM_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20chrono.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20chrono.h index 8014b269e3..6e9ffb3076 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20chrono.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20chrono.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 Ahmad Samir // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20CHRONO_H #define Q20CHRONO_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20functional.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20functional.h index a39b4fceb3..59de3be444 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20functional.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20functional.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20FUNCTIONAL_H #define Q20FUNCTIONAL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20iterator.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20iterator.h index bc1ec0136b..9941459f3c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20iterator.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20iterator.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef Q20ITERATOR_H #define Q20ITERATOR_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20map.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20map.h index c719067480..d5b99701f5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20map.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20map.h @@ -1,6 +1,7 @@ // Copyright (C) 2023 Ahmad Samir // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef Q20MAP_H #define Q20MAP_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20memory.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20memory.h index 6dd4bf5afa..29472b6aef 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20memory.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20memory.h @@ -1,6 +1,7 @@ // Copyright (C) 2023 The Qt Company Ltd. // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20MEMORY_H #define Q20MEMORY_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20type_traits.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20type_traits.h index 97614fbab6..182a91f3cc 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20type_traits.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20type_traits.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20TYPE_TRAITS_H #define Q20TYPE_TRAITS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20utility.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20utility.h index 96d89db734..6e8578f255 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20utility.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20utility.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef Q20UTILITY_H #define Q20UTILITY_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q20vector.h b/local/recipes/qt/qtbase/source/src/corelib/global/q20vector.h index 9d312355ea..a448648165 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q20vector.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q20vector.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 Ahmad Samir // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef Q20VECTOR_H #define Q20VECTOR_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q23functional.h b/local/recipes/qt/qtbase/source/src/corelib/global/q23functional.h index ae8f78a3d0..faca5802e7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q23functional.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q23functional.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef Q23FUNCTIONAL_H #define Q23FUNCTIONAL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q23type_traits.h b/local/recipes/qt/qtbase/source/src/corelib/global/q23type_traits.h index 7cf05729ed..538eb70104 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q23type_traits.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q23type_traits.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef Q23TYPE_TRAITS_H #define Q23TYPE_TRAITS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.cpp index 9c5365c547..815c102161 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.h b/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.h index 3ac5d23e32..39834b061e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q23utility.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef Q23UTILITY_H #define Q23UTILITY_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/q26numeric.h b/local/recipes/qt/qtbase/source/src/corelib/global/q26numeric.h index 72a4d49948..8ba579e98c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/q26numeric.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/q26numeric.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef Q26NUMERIC_H #define Q26NUMERIC_H @@ -29,12 +30,12 @@ QT_BEGIN_NAMESPACE namespace q26 { -// Like std::saturate_cast -#ifdef __cpp_lib_saturation_arithmetic -using std::saturate_cast; +// Like std::saturating_cast +#if defined(__cpp_lib_saturation_arithmetic) && __cpp_lib_saturation_arithmetic >= 202603L +using std::saturating_cast; #else template -constexpr auto saturate_cast(From x) +constexpr auto saturating_cast(From x) { static_assert(std::is_integral_v); static_assert(std::is_integral_v); @@ -62,6 +63,12 @@ constexpr auto saturate_cast(From x) } #endif // __cpp_lib_saturation_arithmetic +template +constexpr auto saturate_cast(From x) +{ + return q26::saturating_cast(x); +} + } // namespace q26 QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.cpp index da75ec0f37..621a1a2b25 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 Aurélien Brooke // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qalloc.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.h b/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.h index a05c09ac63..5eae889e7c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qalloc.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 Aurélien Brooke // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QALLOC_H #define QALLOC_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qassert.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.cpp index 2741077977..3252abe7db 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qassert.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qassert.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h index 7097eaae62..21601391c8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QASSERT_H #define QASSERT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h.orig b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h.orig new file mode 100644 index 0000000000..310e39515b --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qassert.h.orig @@ -0,0 +1,148 @@ +// Copyright (C) 2022 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 +// Qt-Security score:significant reason:default + +#ifndef QASSERT_H +#define QASSERT_H + +#include +#include +#include +#include + +#if 0 +#pragma qt_class(QtAssert) +#pragma qt_sync_stop_processing +#endif + +QT_BEGIN_NAMESPACE + +#if defined(__cplusplus) + +#if !defined(Q_CC_MSVC_ONLY) +Q_NORETURN +#endif +Q_DECL_COLD_FUNCTION +Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line) noexcept; + +#if !defined(Q_ASSERT) +# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) +# define Q_ASSERT(cond) static_cast(false && (cond)) +# else +# define Q_ASSERT(cond) ((cond) ? static_cast(0) : QT_PREPEND_NAMESPACE(qt_assert)(#cond, __FILE__, __LINE__)) +# endif +#endif + +#if !defined(Q_CC_MSVC_ONLY) +Q_NORETURN +#endif +Q_DECL_COLD_FUNCTION +Q_CORE_EXPORT +void qt_assert_x(const char *where, const char *what, const char *file, int line) noexcept; +inline bool qt_no_assert_x(bool, const char *, const char *) noexcept { return false; } + +#if !defined(Q_ASSERT_X) +# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) +# define Q_ASSERT_X(cond, where, what) \ + static_cast(false && QT_PREPEND_NAMESPACE(qt_no_assert_x)(bool(cond), where, what)) +# else +# define Q_ASSERT_X(cond, where, what) ((cond) ? static_cast(0) : QT_PREPEND_NAMESPACE(qt_assert_x)(where, what, __FILE__, __LINE__)) +# endif +#endif + +#ifndef Q_PRE +# define Q_PRE(cond) \ + Q_ASSERT(cond) /* for now... */ +#endif + +#ifndef Q_PRE_X +# define Q_PRE_X(cond, what) \ + Q_ASSERT_X(cond, Q_FUNC_INFO, what) /* for now... */ +#endif + +Q_NORETURN Q_CORE_EXPORT void qt_check_pointer(const char *, int) noexcept; +Q_NORETURN Q_DECL_COLD_FUNCTION +Q_CORE_EXPORT void qBadAlloc(); + +#ifdef QT_NO_EXCEPTIONS +# if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) +# define Q_CHECK_PTR(p) qt_noop() +# else +# define Q_CHECK_PTR(p) do {if (!(p)) QT_PREPEND_NAMESPACE(qt_check_pointer)(__FILE__,__LINE__);} while (false) +# endif +#else +# define Q_CHECK_PTR(p) do { if (!(p)) QT_PREPEND_NAMESPACE(qBadAlloc)(); } while (false) +#endif + +template +inline T *q_check_ptr(T *p) { Q_CHECK_PTR(p); return p; } + +// Q_UNREACHABLE_IMPL() and Q_ASSUME_IMPL() used below are defined in qcompilerdetection.h +#define Q_UNREACHABLE() \ + do {\ + Q_ASSERT_X(false, "Q_UNREACHABLE()", "Q_UNREACHABLE was reached");\ + Q_UNREACHABLE_IMPL();\ + } while (false) + +#ifndef Q_UNREACHABLE_RETURN +# ifdef Q_COMPILER_COMPLAINS_ABOUT_RETURN_AFTER_UNREACHABLE +# define Q_UNREACHABLE_RETURN(...) Q_UNREACHABLE() +# else +# define Q_UNREACHABLE_RETURN(...) do { Q_UNREACHABLE(); return __VA_ARGS__; } while (0) +# endif +#endif + +Q_DECL_DEPRECATED_X("Q_ASSUME() is deprecated because it can produce worse code than when it's absent; " + "use C++23 [[assume]] instead") +inline bool qt_assume_is_deprecated(bool cond) noexcept { return cond; } +#define Q_ASSUME(Expr) \ + [] (bool valueOfExpression) {\ + Q_ASSERT_X(valueOfExpression, "Q_ASSUME()", "Assumption in Q_ASSUME(\"" #Expr "\") was not correct");\ + Q_ASSUME_IMPL(valueOfExpression);\ + }(qt_assume_is_deprecated(Expr)) + + +#if __has_builtin(__builtin_assume) +// Clang has this intrinsic and won't warn about its use in C++20 mode +# define Q_PRESUME_IMPL(assumption) __builtin_assume(assumption) +#elif __has_cpp_attribute(assume) +// GCC has implemented this attribute and allows its use in C++20 mode +# define Q_PRESUME_IMPL(assumption) [[assume(assumption)]] +#elif defined(Q_CC_MSVC) +# define Q_PRESUME_IMPL(assumption) __assume(assumption) +#else +# define Q_PRESUME_IMPL(assumption) (void)0 +#endif + +#define Q_PRESUME(assumption) \ + [&] { \ + Q_ASSERT(assumption); \ + Q_PRESUME_IMPL(assumption); \ + }() + +// Don't use these in C++ mode, use static_assert directly. +// These are here only to keep old code compiling. +# define Q_STATIC_ASSERT(Condition) static_assert(bool(Condition), #Condition) +# define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message) + +#elif defined(Q_COMPILER_STATIC_ASSERT) +// C11 mode - using the _S version in case doesn't do the right thing +# define Q_STATIC_ASSERT(Condition) _Static_assert(!!(Condition), #Condition) +# define Q_STATIC_ASSERT_X(Condition, Message) _Static_assert(!!(Condition), Message) +#else +// C89 & C99 version +# define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) +# define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B +# ifdef __COUNTER__ +# define Q_STATIC_ASSERT(Condition) \ + typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) [(Condition) ? 1 : -1]; +# else +# define Q_STATIC_ASSERT(Condition) \ + typedef char Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) [(Condition) ? 1 : -1]; +# endif /* __COUNTER__ */ +# define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition) +#endif // __cplusplus + +QT_END_NAMESPACE + +#endif // QASSERT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcheckedint_impl.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcheckedint_impl.h index f4081da8bb..9cc2a9299d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcheckedint_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcheckedint_impl.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCHECKEDINT_H #define QCHECKEDINT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.cpp index f30546206a..beb9fb0a17 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #include "qcompare.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.h index f4a1f38124..2c1c10c420 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef QCOMPARE_H #define QCOMPARE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare_impl.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare_impl.h index 7c6b5191de..9798acca11 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcompare_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcompare_impl.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCOMPARE_IMPL_H #define QCOMPARE_IMPL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcomparehelpers.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcomparehelpers.h index 6207af1e9d..8c0e6adc4f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcomparehelpers.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcomparehelpers.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef QCOMPARE_H #error "Do not include qcomparehelpers.h directly. Use qcompare.h instead." diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcompilerdetection.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcompilerdetection.h index 58a6611a78..3793139b45 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcompilerdetection.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcompilerdetection.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if 0 #pragma qt_class(QtCompilerDetection) @@ -1195,7 +1196,8 @@ # define QT_WARNING_DISABLE_INTEL(number) # define QT_WARNING_DISABLE_CLANG(text) # define QT_WARNING_DISABLE_GCC(text) -# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_MSVC(4996) +# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_MSVC(4996) \ + QT_WARNING_DISABLE_MSVC(4995) # define QT_WARNING_DISABLE_FLOAT_COMPARE # define QT_WARNING_DISABLE_INVALID_OFFSETOF #elif defined(Q_CC_CLANG) @@ -1205,7 +1207,13 @@ # define QT_WARNING_DISABLE_GCC(text) # define QT_WARNING_DISABLE_INTEL(number) # define QT_WARNING_DISABLE_MSVC(number) -# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") +# if defined(__has_warning) && __has_warning("-Wdeprecated-pragma") +# define QT_WARNING_DISABLE_DEPRECATED_MACRO QT_WARNING_DISABLE_CLANG("-Wdeprecated-pragma") +# else +# define QT_WARNING_DISABLE_DEPRECATED_MACRO +# endif +# define QT_WARNING_DISABLE_DEPRECATED QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations") \ + QT_WARNING_DISABLE_DEPRECATED_MACRO # define QT_WARNING_DISABLE_FLOAT_COMPARE QT_WARNING_DISABLE_CLANG("-Wfloat-equal") # define QT_WARNING_DISABLE_INVALID_OFFSETOF QT_WARNING_DISABLE_CLANG("-Winvalid-offsetof") #elif defined(Q_CC_GNU) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) @@ -1327,9 +1335,8 @@ #endif // __cplusplus #if defined(__cplusplus) && defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) -# if Q_CC_MSVC < 1927 - // Check below only works with 16.7 or newer -# error "Qt requires at least Visual Studio 2019 version 16.7 (VC++ version 14.27). Please upgrade." +# if Q_CC_MSVC < 1930 +# error "Qt requires at least Visual Studio 2022 (MSVC version 19.30 or newer). Please upgrade." # endif // On MSVC we require /permissive- set by user code. Check that we are diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qconfig-bootstrapped.h b/local/recipes/qt/qtbase/source/src/corelib/global/qconfig-bootstrapped.h index 09de82985e..bef0e253a3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qconfig-bootstrapped.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qconfig-bootstrapped.h @@ -14,6 +14,7 @@ // Despite its file name, this really is not a public header. // It is an implementation detail of the private bootstrap library. // +// Qt-Security score:significant reason:default #if 0 // silence syncqt warnings diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qconstructormacros.h b/local/recipes/qt/qtbase/source/src/corelib/global/qconstructormacros.h index 21492ac31f..243bc8f4d7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qconstructormacros.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qconstructormacros.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QCONSTRUCTORMACROS_H #define QCONSTRUCTORMACROS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qcontainerinfo.h b/local/recipes/qt/qtbase/source/src/corelib/global/qcontainerinfo.h index 14468510a5..5720af76c4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qcontainerinfo.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qcontainerinfo.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QCONTAINERINFO_H #define QCONTAINERINFO_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qdarwinhelpers.h b/local/recipes/qt/qtbase/source/src/corelib/global/qdarwinhelpers.h index ad72211663..d5f067b97e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qdarwinhelpers.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qdarwinhelpers.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTDARWINHELPERS_H #define QTDARWINHELPERS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qendian.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qendian.cpp index 1436316ac1..f1f0aaa985 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qendian.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qendian.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2018 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qendian.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qendian.h b/local/recipes/qt/qtbase/source/src/corelib/global/qendian.h index 8c3b5e4374..8e0429adb2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qendian.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qendian.h @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QENDIAN_H #define QENDIAN_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qendian_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qendian_p.h index 1789e54ac8..c94a3f5e98 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qendian_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qendian_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QENDIAN_P_H #define QENDIAN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qexceptionhandling.h b/local/recipes/qt/qtbase/source/src/corelib/global/qexceptionhandling.h index 6c547a9063..7b116d3c30 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qexceptionhandling.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qexceptionhandling.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QEXCEPTIONHANDLING_H #define QEXCEPTIONHANDLING_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qexpected_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qexpected_p.h index 54bcae5110..e9600ba933 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qexpected_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qexpected_p.h @@ -15,6 +15,7 @@ // along with this software. If not, see // . /// +// Qt-Security score:significant reason:default #ifndef Q23_TL_EXPECTED_HPP #define Q23_TL_EXPECTED_HPP diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qflags.h b/local/recipes/qt/qtbase/source/src/corelib/global/qflags.h index 1c1e2ef04d..88580ed4ef 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qflags.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qflags.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QFLAGS_H #define QFLAGS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.cpp index 4c0de7fcee..0b2e244b45 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2016 by Southwest Research Institute (R) // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qfloat16.h" #include "private/qsimd_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.h b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.h index a075b3ec07..0a2677cb8a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 by Southwest Research Institute (R) // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFLOAT16_H #define QFLOAT16_H @@ -124,7 +125,7 @@ public: #if QT_CONFIG(signaling_nan) static constexpr qfloat16 _limit_signaling_NaN() noexcept { return qfloat16(Wrap(0x7d00)); } #endif -#endif +#endif // __STDCPP_FLOAT16_T__ inline constexpr bool isNormal() const noexcept { return (b16 & 0x7c00) && (b16 & 0x7c00) != 0x7c00; } private: @@ -447,7 +448,7 @@ inline auto qHypot(qfloat16 x, qfloat16 y) { #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) || QFLOAT16_IS_NATIVE return QtPrivate::QHypotHelper(x).add(y).result(); -#else +#else // NearestFloat is float: return qfloat16(qHypot(float(x), float(y))); #endif } @@ -458,6 +459,14 @@ template auto qHypot(F first, Fs... rest); template typename QtPrivate::QHypotType::type qHypot(T x, qfloat16 y) { + // Two-arg qHypot() delegates to std::hypot(), which has no (T = double, + // NearestFloat = __fp16) overload on ARM64 Linux, leading to ambiguity in + // (at least) that case. Testing whether we can use it needs C++20 ... +#ifdef __cpp_concepts + if constexpr (requires { std::hypot(x, qfloat16::NearestFloat(y)); }) + return qHypot(x, qfloat16::NearestFloat(y)); + else +#endif if constexpr (std::is_floating_point_v) return qHypot(x, float(y)); else @@ -469,7 +478,7 @@ template auto qHypot(qfloat16 x, T y) } #if defined(__cpp_lib_hypot) && __cpp_lib_hypot >= 201603L // Expected to be true -// If any are not qfloat16, convert each qfloat16 to float: +// If any are not qfloat16, convert each qfloat16 to qfloat16::NearestFloat: /* (The following splits the some-but-not-all-qfloat16 cases up, using (X|Y|Z)&~(X&Y&Z) = X ? ~(Y&Z) : Y|Z = X&~(Y&Z) | ~X&Y | ~X&~Y&Z, into non-overlapping cases, to avoid ambiguity.) */ @@ -494,7 +503,7 @@ inline auto qHypot(qfloat16 x, qfloat16 y, qfloat16 z) { #if (defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)) || QFLOAT16_IS_NATIVE return QtPrivate::QHypotHelper(x).add(y).add(z).result(); -#else +#else // NearestFloat is float; return qfloat16(qHypot(float(x), float(y), float(z))); #endif } diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16tables.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16tables.cpp index 4aa620c4e7..fc6b69bb4f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16tables.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qfloat16tables.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2019 Intel Corporation. // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default /* This file was generated by util/qfloat16-tables/gen_qfloat16_tables.cpp */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qforeach.h b/local/recipes/qt/qtbase/source/src/corelib/global/qforeach.h index ab0e20b989..efccfb188c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qforeach.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qforeach.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFOREACH_H #define QFOREACH_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qfunctionpointer.h b/local/recipes/qt/qtbase/source/src/corelib/global/qfunctionpointer.h index 3884954f89..1fe60ade4f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qfunctionpointer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qfunctionpointer.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QFUNCTIONPOINTER_H #define QFUNCTIONPOINTER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qgettid_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qgettid_p.h index 3f1f0afc8d..9f0265c259 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qgettid_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qgettid_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QGETTID_P_H #define QGETTID_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.cpp index 325e0b39a6..c2dbaddde1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qplatformdefs.h" #include "qstring.h" @@ -361,7 +362,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters) \row \li 6.8.0 \li The qAsConst() function (see \l{QT_NO_QASCONST}) \row \li 6.8.0 \li File-related I/O classes have their \c{open()} functions marked \c{[[nodiscard]]} (see \l{QT_USE_NODISCARD_FILE_OPEN}) \row\li 6.9.0 \li The qsnprintf() and qvnprintf() functions (see \l{QT_NO_QSNPRINTF}). - \row\li 6.11.0 \li Support for qHash overloads without a seed (see \l{QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD}). + \row\li 6.12.0 \li Support for qHash overloads without a seed (see \l{QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD}). \endtable Moreover, individual APIs may also get disabled as part of the diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.h b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.h index 07fc99b20b..47d8c14e33 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QGLOBAL_H #define QGLOBAL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal_p.h index 1911d3c3e7..0eb69efbe0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qglobal_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qglobal_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2017 The Qt Company Ltd. // Copyright (C) 2015 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QGLOBAL_P_H #define QGLOBAL_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qglobalstatic.h b/local/recipes/qt/qtbase/source/src/corelib/global/qglobalstatic.h index 928d763d50..216044c177 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qglobalstatic.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qglobalstatic.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QGLOBALSTATIC_H #define QGLOBALSTATIC_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qhooks.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qhooks.cpp index 414b96aac3..5f32e129cd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qhooks.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qhooks.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Volker Krause // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qhooks_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qhooks_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qhooks_p.h index e266c2a7f9..cb0ed85011 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qhooks_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qhooks_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Volker Krause // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QHOOKS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo.h b/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo.h index 10225a8adc..3524239f02 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QLIBRARYINFO_H #define QLIBRARYINFO_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo_p.h index b9ca6b4d18..ec348d9069 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qlibraryinfo_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QLIBRARYINFO_P_H #define QLIBRARYINFO_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.cpp index aa37bd2268..8021af7e4f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2016 Olivier Goffart // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qlogging.h" #include "qlogging_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.h b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.h index ebb5c1ea05..f3bb573ec3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QLOGGING_H #define QLOGGING_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging_p.h index 9122524f8b..910d14fa36 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qlogging_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qlogging_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2018 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 +// Qt-Security score:significant reason:default #ifndef QLOGGING_P_H #define QLOGGING_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.cpp index d413a35c6b..5e9f044f7b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qmalloc.h" #include "qplatformdefs.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.h b/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.h index 83dfff358b..c372a09ed8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qmalloc.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QMALLOC_H #define QMALLOC_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qminmax.h b/local/recipes/qt/qtbase/source/src/corelib/global/qminmax.h index fca13e047e..3e3ffd82d1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qminmax.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qminmax.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QMINMAX_H #define QMINMAX_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.h b/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.h index 8332d1fd9b..9e8d31ed9f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2020 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QNAMESPACE_H #define QNAMESPACE_H @@ -1893,6 +1894,16 @@ public: DockCount }; + enum CallMode { + Testing, + Live, + }; + + enum SaveStateRule { + KeepSavedState, + ClearSavedState, + }; + enum Callback { EventNotifyCallback, LastCallback diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.qdoc b/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.qdoc index 69418af4b6..a88124754d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qnamespace.qdoc @@ -830,6 +830,18 @@ \value Dark The background colors are darker than the text color, i.e. the theme is dark. */ +/*! + \enum Qt::ContrastPreference + \since 6.10 + + Represents the user's preferred contrast setting. + Styles can honor this setting by increasing the contrast of foreground and background colors, + as well as giving widgets and controls thicker borders. + + \value NoPreference No specific preferences. + \value HighContrast The user prefers the application to be in high contrast. +*/ + /*! \enum Qt::ImageConversionFlag @@ -2291,16 +2303,28 @@ \value WindowMinimizeButtonHint Adds a minimize button. On some platforms this implies Qt::WindowSystemMenuHint for it to work. + \note On many Wayland-based systems, button hints are not supported for + server-side decorations. + \value WindowMaximizeButtonHint Adds a maximize button. On some platforms this implies Qt::WindowSystemMenuHint for it to work. + \note On many Wayland-based systems, button hints are not supported for + server-side decorations. + \value WindowMinMaxButtonsHint Adds a minimize and a maximize button. On some platforms this implies Qt::WindowSystemMenuHint for it to work. + \note On many Wayland-based systems, button hints are not supported for + server-side decorations. + \value WindowCloseButtonHint Adds a close button. On some platforms this implies Qt::WindowSystemMenuHint for it to work. + \note On many Wayland-based systems, button hints are not supported for + server-side decorations. + \value WindowContextHelpButtonHint Adds a context help button to dialogs. On some platforms this implies Qt::WindowSystemMenuHint for it to work. @@ -2661,8 +2685,15 @@ \value ImhHiddenText The input method should not show the characters while typing. This is automatically set when setting QLineEdit::echoMode to \c Password. Note that setting \c ImhHiddenText does not change the echo mode. + + Note that Android IMEs deliberately only + allow Latin/ASCII character input for password fields. \value ImhSensitiveData Typed text should not be stored by the active input method in any persistent storage like predictive user dictionary. + + Note that the Qt Framework treats this as a visible password + and in this case Android IMEs deliberately only + allow Latin/ASCII character input. \value ImhNoAutoUppercase The input method should not try to automatically switch to upper case when a sentence ends. \value ImhPreferNumbers Numbers are preferred (but not required). diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface.h b/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface.h index 89f33651c5..9bcf2ae3bf 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QNATIVEINTERFACE_H #define QNATIVEINTERFACE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface_p.h index 6f90bccb46..bcd89943c7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qnativeinterface_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QNATIVEINTERFACE_P_H #define QNATIVEINTERFACE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qnumeric_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qnumeric_p.h index fe0f8e1ab6..7d55777e5b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qnumeric_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qnumeric_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QNUMERIC_P_H #define QNUMERIC_P_H @@ -23,7 +24,7 @@ #include #include -#include // temporarily, for saturate_cast +#include // temporarily, for saturating_cast #ifndef __has_extension # define __has_extension(X) 0 @@ -436,7 +437,7 @@ template bool mul_overflow(T v1, T *r) template static constexpr auto qt_saturate(From x) { - return q26::saturate_cast(x); + return q26::saturating_cast(x); } QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.cpp index 3fcf0b2cad..4ca7fb8536 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qoperatingsystemversion.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.h b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.h index b7467cba83..48d24d6f4e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include #include @@ -263,7 +264,7 @@ public: { } - QT_CORE_INLINE_SINCE(6, 11) + QT_CORE_INLINE_SINCE(6, 3) static QOperatingSystemVersion current(); static constexpr OSType currentType() @@ -304,12 +305,12 @@ class QDebug; Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov); #endif -#if QT_CORE_INLINE_IMPL_SINCE(6, 11) +#if QT_CORE_INLINE_IMPL_SINCE(6, 3) QOperatingSystemVersion QOperatingSystemVersion::current() { return QOperatingSystemVersionBase::current(); } -#endif // QT_CORE_INLINE_IMPL_SINCE(6, 11) +#endif // QT_CORE_INLINE_IMPL_SINCE(6, 3) QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_p.h index 5d1480d524..1b24cde943 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QOPERATINGSYSTEMVERSION_P_H #define QOPERATINGSYSTEMVERSION_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win.cpp index a209fb17b6..cdfcc5ec49 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qoperatingsystemversion_win_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win_p.h index 92fc0e12f3..e38b005a66 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoperatingsystemversion_win_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #ifndef QOPERATINGSYSTEMVERSION_WIN_P_H #define QOPERATINGSYSTEMVERSION_WIN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qoverload.h b/local/recipes/qt/qtbase/source/src/corelib/global/qoverload.h index 9376e1e246..251968e35a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qoverload.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qoverload.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QOVERLOAD_H #define QOVERLOAD_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qprocessordetection.h b/local/recipes/qt/qtbase/source/src/corelib/global/qprocessordetection.h index 83018e72ec..7dbd38d316 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qprocessordetection.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qprocessordetection.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if 0 diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qrandom_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qrandom_p.h index e3206c2e5e..5eb76ceca3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qrandom_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qrandom_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QRANDOM_P_H #define QRANDOM_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp index 3169d28e09..141920f06c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // we need ICC to define the prototype for _rdseed64_step +// Qt-Security score:significant reason:default #define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES #undef _FORTIFY_SOURCE // otherwise, the always_inline from stdio.h fail to inline @@ -10,6 +11,7 @@ #include "qalgorithms.h" #include +#include #include #if defined(QT_NO_DEBUG) && !defined(NDEBUG) @@ -377,7 +379,11 @@ inline quint64 _xgetbv(__int64) { return 0; } #endif static void xgetbv(uint in, uint &eax, uint &edx) { -#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS) +#ifdef Q_OS_REDOX + Q_UNUSED(in); + eax = 0; + edx = 0; +#elif (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS) asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction : "=a" (eax), "=d" (edx) : "c" (in)); diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp.orig b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp.orig new file mode 100644 index 0000000000..b9c7bf58e5 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.cpp.orig @@ -0,0 +1,715 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// we need ICC to define the prototype for _rdseed64_step +// Qt-Security score:significant reason:default +#define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES +#undef _FORTIFY_SOURCE // otherwise, the always_inline from stdio.h fail to inline + +#include "qsimd_p.h" +#include "qalgorithms.h" + +#include +#include +#include + +#if defined(QT_NO_DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif +#include + +#ifdef Q_OS_LINUX +# include "../testlib/3rdparty/valgrind/valgrind_p.h" +#endif + +#define QT_FUNCTION_TARGET_BASELINE + +#if defined(Q_OS_WIN) +# if !defined(Q_CC_GNU) +# include +# endif +# if defined(Q_PROCESSOR_ARM_64) +# include +# include +# endif +#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_MIPS_32) +# include "private/qcore_unix_p.h" +#elif QT_CONFIG(getauxval) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_LOONGARCH)) +# include + +// the kernel header definitions for HWCAP_* +// (the ones we need/may need anyway) + +// copied from (ARM) +#define HWCAP_NEON 4096 + +// copied from (ARM): +#define HWCAP2_AES (1 << 0) +#define HWCAP2_CRC32 (1 << 4) + +// copied from (Aarch64) +#define HWCAP_AES (1 << 3) +#define HWCAP_CRC32 (1 << 7) +#define HWCAP_SVE (1 << 22) + +// copied from +#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#define AT_HWCAP2 26 /* extension of AT_HWCAP */ + +#elif defined(Q_CC_GHS) +# include +#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM) +# include +#endif + +QT_BEGIN_NAMESPACE + +template QT_FUNCTION_TARGET_BASELINE +uint arraysize(T (&)[N]) +{ + // Same as std::size, but with QT_FUNCTION_TARGET_BASELIE, + // otherwise some versions of GCC fail to compile. + return N; +} + +#if defined(Q_PROCESSOR_ARM) +/* Data: + neon + crc32 + aes + sve + */ +static const char features_string[] = + "\0" + " neon\0" + " crc32\0" + " aes\0" + " sve\0"; +static const int features_indices[] = { 0, 1, 7, 14, 19 }; +#elif defined(Q_PROCESSOR_MIPS) +/* Data: + dsp + dspr2 +*/ +static const char features_string[] = + "\0" + " dsp\0" + " dspr2\0"; + +static const int features_indices[] = { + 0, 1, 6 +}; +#elif defined(Q_PROCESSOR_LOONGARCH) +/* Data: + lsx + lasx +*/ +static const char features_string[] = + "\0" + " lsx\0" + " lasx\0"; + +static const int features_indices[] = { + 0, 1, 6 +}; +#elif defined(Q_PROCESSOR_X86) +# include "qsimd_x86.cpp" // generated by util/x86simdgen +#else +static const char features_string[] = ""; +static const int features_indices[] = { 0 }; +#endif +// end generated + +#if defined(Q_PROCESSOR_ARM) +static inline quint64 detectProcessorFeatures() +{ + quint64 features = 0; + +#if QT_CONFIG(getauxval) + unsigned long auxvHwCap = getauxval(AT_HWCAP); + if (auxvHwCap != 0) { +# if defined(Q_PROCESSOR_ARM_64) + // For Aarch64: + features |= CpuFeatureNEON; // NEON is always available + if (auxvHwCap & HWCAP_CRC32) + features |= CpuFeatureCRC32; + if (auxvHwCap & HWCAP_AES) + features |= CpuFeatureAES; + if (auxvHwCap & HWCAP_SVE) + features |= CpuFeatureSVE; +# else + // For ARM32: + if (auxvHwCap & HWCAP_NEON) + features |= CpuFeatureNEON; + auxvHwCap = getauxval(AT_HWCAP2); + if (auxvHwCap & HWCAP2_CRC32) + features |= CpuFeatureCRC32; + if (auxvHwCap & HWCAP2_AES) + features |= CpuFeatureAES; +# endif + return features; + } + // fall back to compile-time flags if getauxval failed +#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM) + unsigned feature; + size_t len = sizeof(feature); + Q_UNUSED(len); +#if defined(__ARM_NEON) + features |= CpuFeatureNEON; +#else + #error "Misconfiguration, NEON should always be enabled on Apple hardware" +#endif +#if defined(__ARM_FEATURE_CRC32) + features |= CpuFeatureCRC32; +#elif defined(Q_OS_MACOS) + #error "Misconfiguration, CRC32 should always be enabled on Apple desktop hardware" +#else + if (sysctlbyname("hw.optional.armv8_crc32", &feature, &len, nullptr, 0) == 0) + features |= feature ? CpuFeatureCRC32 : 0; +#endif +#if defined(__ARM_FEATURE_CRYPTO) + features |= CpuFeatureAES; +#elif defined(Q_OS_MACOS) + #error "Misconfiguration, CRYPTO/AES should always be enabled on Apple desktop hardware" +#else + if (sysctlbyname("hw.optional.arm.FEAT_AES", &feature, &len, nullptr, 0) == 0) + features |= feature ? CpuFeatureAES : 0; +#endif +#if defined(__ARM_FEATURE_SVE) + features |= CpuFeatureSVE; +#else + if (sysctlbyname("hw.optional.arm.FEAT_SVE", &feature, &len, nullptr, 0) == 0) + features |= feature ? CpuFeatureSVE : 0; +#endif + return features; +#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM_64) + features |= CpuFeatureNEON; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0) + features |= CpuFeatureCRC32; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) + features |= CpuFeatureAES; + return features; +#endif +#if defined(__ARM_NEON__) + features |= CpuFeatureNEON; +#endif +#if defined(__ARM_FEATURE_CRC32) + features |= CpuFeatureCRC32; +#endif +#if defined(__ARM_FEATURE_CRYPTO) + features |= CpuFeatureAES; +#endif +#if defined(__ARM_FEATURE_SVE) + features |= CpuFeatureSVE; +#endif + + return features; +} + +#elif defined(Q_PROCESSOR_LOONGARCH) +static inline quint64 detectProcessorFeatures() +{ + quint64 features = 0; +# if QT_CONFIG(getauxval) + quint64 hwcap = getauxval(AT_HWCAP); + + if (hwcap & HWCAP_LOONGARCH_LSX) + features |= CpuFeatureLSX; + if (hwcap & HWCAP_LOONGARCH_LASX) + features |= CpuFeatureLASX; +# else + enum LoongArchFeatures { + LOONGARCH_CFG2 = 0x2, + LOONGARCH_CFG2_LSX = (1 << 6), + LOONGARCH_CFG2_LASX = (1 << 7) + }; + + quint64 reg = 0; + + __asm__ volatile( + "cpucfg %0, %1 \n\t" + : "+&r"(reg) + : "r"(LOONGARCH_CFG2) + ); + + if (reg & LOONGARCH_CFG2_LSX) + features |= CpuFeatureLSX; + if (reg & LOONGARCH_CFG2_LASX) + features |= CpuFeatureLASX; +# endif + return features; +} + +#elif defined(Q_PROCESSOR_X86) + +#ifdef Q_PROCESSOR_X86_32 +# define PICreg "%%ebx" +#else +# define PICreg "%%rbx" +#endif +#ifdef __SSE2_MATH__ +# define X86_BASELINE "no-sse3" +#else +# define X86_BASELINE "no-sse" +#endif + +#if defined(Q_CC_GNU) || defined(Q_CC_CLANG) +// lower the target for functions in this file +# undef QT_FUNCTION_TARGET_BASELINE +# define QT_FUNCTION_TARGET_BASELINE __attribute__((target(X86_BASELINE))) +#endif + +QT_FUNCTION_TARGET_BASELINE +static int maxBasicCpuidSupported() +{ +#if defined(Q_CC_EMSCRIPTEN) + return 6; // All features supported by Emscripten +#elif defined(Q_CC_GNU) + qregisterint tmp1; + +# if Q_PROCESSOR_X86 < 5 + // check if the CPUID instruction is supported + long cpuid_supported; + asm ("pushf\n" + "pop %0\n" + "mov %0, %1\n" + "xor $0x00200000, %0\n" + "push %0\n" + "popf\n" + "pushf\n" + "pop %0\n" + "xor %1, %0\n" // %eax is now 0 if CPUID is not supported + : "=a" (cpuid_supported), "=r" (tmp1) + ); + if (!cpuid_supported) + return 0; +# endif + + int result; + asm ("xchg " PICreg", %1\n" + "cpuid\n" + "xchg " PICreg", %1\n" + : "=&a" (result), "=&r" (tmp1) + : "0" (0) + : "ecx", "edx"); + return result; +#elif defined(Q_OS_WIN) + // Use the __cpuid function; if the CPUID instruction isn't supported, it will return 0 + int info[4]; + __cpuid(info, 0); + return info[0]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUID(0, info); + return info[0]; +#else + return 0; +#endif +} + +QT_FUNCTION_TARGET_BASELINE +static void cpuidFeatures01(uint &ecx, uint &edx) +{ +#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN) + qregisterint tmp1; + asm ("xchg " PICreg", %2\n" + "cpuid\n" + "xchg " PICreg", %2\n" + : "=&c" (ecx), "=&d" (edx), "=&r" (tmp1) + : "a" (1)); +#elif defined(Q_OS_WIN) + int info[4]; + __cpuid(info, 1); + ecx = info[2]; + edx = info[3]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUID(1, info); + ecx = info[2]; + edx = info[3]; +#else + Q_UNUSED(ecx); + Q_UNUSED(edx); +#endif +} + +#ifdef Q_OS_WIN +inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));} +#endif + +QT_FUNCTION_TARGET_BASELINE +static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx) +{ +#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN) + qregisteruint rbx; // in case it's 64-bit + qregisteruint rcx = 0; + qregisteruint rdx = 0; + asm ("xchg " PICreg", %0\n" + "cpuid\n" + "xchg " PICreg", %0\n" + : "=&r" (rbx), "+&c" (rcx), "+&d" (rdx) + : "a" (7)); + ebx = rbx; + ecx = rcx; + edx = rdx; +#elif defined(Q_OS_WIN) + int info[4]; + __cpuidex(info, 7, 0); + ebx = info[1]; + ecx = info[2]; + edx = info[3]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUIDEX(7, 0, info); + ebx = info[1]; + ecx = info[2]; + edx = info[3]; +#else + Q_UNUSED(ebx); + Q_UNUSED(ecx); + Q_UNUSED(edx); +#endif +} + +QT_FUNCTION_TARGET_BASELINE +#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS)) +// fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int); +inline quint64 _xgetbv(__int64) { return 0; } +#endif +static void xgetbv(uint in, uint &eax, uint &edx) +{ +#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS) + asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction + : "=a" (eax), "=d" (edx) + : "c" (in)); +#elif defined(Q_OS_WIN) + quint64 result = _xgetbv(in); + eax = result; + edx = result >> 32; +#else + Q_UNUSED(in); + Q_UNUSED(eax); + Q_UNUSED(edx); +#endif +} + +QT_FUNCTION_TARGET_BASELINE +static quint64 adjustedXcr0(quint64 xcr0) +{ + /* + * Some OSes hide their capability of context-switching the AVX512 state in + * the XCR0 register. They do that so the first time we execute an + * instruction that may access the AVX512 state (requiring the EVEX prefix) + * they allocate the necessary context switch space. + * + * This behavior is deprecated with the XFD (Extended Feature Disable) + * register, but we can't change existing OSes. + */ +#ifdef Q_OS_DARWIN + // from in xnu + // + constexpr quint64 kHasAVX512F = Q_UINT64_C(0x0000004000000000); + constexpr quintptr commpage = sizeof(void *) > 4 ? Q_UINT64_C(0x00007fffffe00000) : 0xffff0000; + constexpr quintptr cpu_capabilities64 = commpage + 0x10; + quint64 capab = *reinterpret_cast(cpu_capabilities64); + if (capab & kHasAVX512F) + xcr0 |= XSave_Avx512State; +#endif + + return xcr0; +} + +QT_FUNCTION_TARGET_BASELINE +static quint64 detectProcessorFeatures() +{ + quint64 features = 0; + int cpuidLevel = maxBasicCpuidSupported(); +#if Q_PROCESSOR_X86 < 5 + if (cpuidLevel < 1) + return 0; +#else + assert(cpuidLevel >= 1); +#endif + + uint results[X86CpuidMaxLeaf] = {}; + cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]); + if (cpuidLevel >= 7) + cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]); + + // populate our feature list + for (uint i = 0; i < arraysize(x86_locators); ++i) { + uint word = x86_locators[i] / 32; + uint bit = 1U << (x86_locators[i] % 32); + quint64 feature = Q_UINT64_C(1) << i; + if (results[word] & bit) + features |= feature; + } + + // now check the AVX state + quint64 xcr0 = 0; + if (results[Leaf01ECX] & (1u << 27)) { + // XGETBV enabled + uint xgetbvA = 0, xgetbvD = 0; + xgetbv(0, xgetbvA, xgetbvD); + + xcr0 = xgetbvA; + if (sizeof(XSaveBits) > sizeof(xgetbvA)) + xcr0 |= quint64(xgetbvD) << 32; + xcr0 = adjustedXcr0(xcr0); + } + + for (auto req : xsave_requirements) { + if ((xcr0 & req.xsave_state) != req.xsave_state) + features &= ~req.cpu_features; + } + + return features; +} + +#elif defined(Q_PROCESSOR_MIPS_32) + +#if defined(Q_OS_LINUX) +// +// Do not use QByteArray: it could use SIMD instructions itself at +// some point, thus creating a recursive dependency. Instead, use a +// QSimpleBuffer, which has the bare minimum needed to use memory +// dynamically and read lines from /proc/cpuinfo of arbitrary sizes. +// +struct QSimpleBuffer +{ + static const int chunk_size = 256; + char *data; + unsigned alloc; + unsigned size; + + QSimpleBuffer() : data(nullptr), alloc(0), size(0) { } + ~QSimpleBuffer() { ::free(data); } + + void resize(unsigned newsize) + { + if (newsize > alloc) { + unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1); + if (newalloc < newsize) + newalloc = newsize; + if (newalloc != alloc) { + data = static_cast(::realloc(data, newalloc)); + alloc = newalloc; + } + } + size = newsize; + } + void append(const QSimpleBuffer &other, unsigned appendsize) + { + unsigned oldsize = size; + resize(oldsize + appendsize); + ::memcpy(data + oldsize, other.data, appendsize); + } + void popleft(unsigned amount) + { + if (amount >= size) + return resize(0); + size -= amount; + ::memmove(data, data + amount, size); + } + char *cString() + { + if (!alloc) + resize(1); + return (data[size] = '\0', data); + } +}; + +// +// Uses a scratch "buffer" (which must be used for all reads done in the +// same file descriptor) to read chunks of data from a file, to read +// one line at a time. Lines include the trailing newline character ('\n'). +// On EOF, line.size is zero. +// +static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer) +{ + for (;;) { + char *newline = static_cast(::memchr(buffer.data, '\n', buffer.size)); + if (newline) { + unsigned piece_size = newline - buffer.data + 1; + line.append(buffer, piece_size); + buffer.popleft(piece_size); + line.resize(line.size - 1); + return; + } + if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) { + int oldsize = buffer.size; + buffer.resize(buffer.size + QSimpleBuffer::chunk_size); + buffer.size = oldsize; + } + ssize_t read_bytes = + ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size); + if (read_bytes > 0) + buffer.size += read_bytes; + else + return; + } +} + +// +// Checks if any line with a given prefix from /proc/cpuinfo contains +// a certain string, surrounded by spaces. +// +static bool procCpuinfoContains(const char *prefix, const char *string) +{ + int cpuinfo_fd = ::qt_safe_open("/proc/cpuinfo", O_RDONLY); + if (cpuinfo_fd == -1) + return false; + + unsigned string_len = ::strlen(string); + unsigned prefix_len = ::strlen(prefix); + QSimpleBuffer line, buffer; + bool present = false; + do { + line.resize(0); + bufReadLine(cpuinfo_fd, line, buffer); + char *colon = static_cast(::memchr(line.data, ':', line.size)); + if (colon && line.size > prefix_len + string_len) { + if (!::strncmp(prefix, line.data, prefix_len)) { + // prefix matches, next character must be ':' or space + if (line.data[prefix_len] == ':' || ::isspace(line.data[prefix_len])) { + // Does it contain the string? + char *found = ::strstr(line.cString(), string); + if (found && ::isspace(found[-1]) && + (::isspace(found[string_len]) || found[string_len] == '\0')) { + present = true; + break; + } + } + } + } + } while (line.size); + + ::qt_safe_close(cpuinfo_fd); + return present; +} +#endif + +static inline quint64 detectProcessorFeatures() +{ + // NOTE: MIPS 74K cores are the only ones supporting DSPr2. + quint64 flags = 0; + +#if defined __mips_dsp + flags |= CpuFeatureDSP; +# if defined __mips_dsp_rev && __mips_dsp_rev >= 2 + flags |= CpuFeatureDSPR2; +# elif defined(Q_OS_LINUX) + if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) + flags |= CpuFeatureDSPR2; +# endif +#elif defined(Q_OS_LINUX) + if (procCpuinfoContains("ASEs implemented", "dsp")) { + flags |= CpuFeatureDSP; + if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) + flags |= CpuFeatureDSPR2; + } +#endif + + return flags; +} + +#else +static inline uint detectProcessorFeatures() +{ + return 0; +} +#endif + +// record what CPU features were enabled by default in this Qt build +static const quint64 minFeature = qCompilerCpuFeatures; + +static constexpr auto SimdInitialized = QCpuFeatureType(1) << (sizeof(QCpuFeatureType) * 8 - 1); +Q_ATOMIC(QCpuFeatureType) QT_MANGLE_NAMESPACE(qt_cpu_features)[1] = { 0 }; + +QT_FUNCTION_TARGET_BASELINE +uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)() +{ + auto minFeatureTest = minFeature; +#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk) + // Controlflow Enforcement Technology (CET) is an OS-assisted + // hardware-feature, meaning the CPUID bit may be disabled if the OS + // doesn't support it, but that's ok. + minFeatureTest &= ~CpuFeatureSHSTK; +#endif + QCpuFeatureType f = detectProcessorFeatures(); + + // Intentionally NOT qgetenv (this code runs too early) + if (char *disable = getenv("QT_NO_CPU_FEATURE"); disable && *disable) { +#if _POSIX_C_SOURCE >= 200112L + char *saveptr = nullptr; + auto strtok = [&saveptr](char *str, const char *delim) { + return ::strtok_r(str, delim, &saveptr); + }; +#endif + while (char *token = strtok(disable, " ")) { + disable = nullptr; + for (uint i = 0; i < arraysize(features_indices); ++i) { + if (strcmp(token, features_string + features_indices[i]) == 0) + f &= ~(Q_UINT64_C(1) << i); + } + } + } + +#ifdef RUNNING_ON_VALGRIND + bool runningOnValgrind = RUNNING_ON_VALGRIND; +#else + bool runningOnValgrind = false; +#endif + if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) { + quint64 missing = minFeatureTest & ~quint64(f); + fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n "); + for (uint i = 0; i < arraysize(features_indices); ++i) { + if (missing & (Q_UINT64_C(1) << i)) + fprintf(stderr, "%s", features_string + features_indices[i]); + } + fprintf(stderr, "\n"); + fflush(stderr); + qAbort(); + } + + assert((f & SimdInitialized) == 0); + f |= SimdInitialized; + std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f, std::memory_order_relaxed); + return f; +} + +QT_FUNCTION_TARGET_BASELINE +void qDumpCPUFeatures() +{ + quint64 features = detectProcessorFeatures() & ~SimdInitialized; + printf("Processor features: "); + for (uint i = 0; i < arraysize(features_indices); ++i) { + if (features & (Q_UINT64_C(1) << i)) + printf("%s%s", features_string + features_indices[i], + minFeature & (Q_UINT64_C(1) << i) ? "[required]" : ""); + } + if ((features = (qCompilerCpuFeatures & ~features))) { + printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:"); + for (uint i = 0; i < arraysize(features_indices); ++i) { + if (features & (Q_UINT64_C(1) << i)) + printf("%s", features_string + features_indices[i]); + } + printf("\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!"); + } + puts(""); +} + +#if QT_SUPPORTS_INIT_PRIORITY +namespace { +struct QSimdInitializer +{ + inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); } +}; +} + +// This is intentionally a dynamic initialization of the variable +Q_DECL_INIT_PRIORITY(01) static QSimdInitializer initializer; +#endif + +QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.h b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.h index 86af5b7d17..a1a66a523d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSIMD_H #define QSIMD_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_p.h index 223cffe250..6d4c4536aa 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSIMD_P_H #define QSIMD_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86.cpp index a3c389d58a..4bb929e456 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // This is a generated file. DO NOT EDIT. // Please see util/x86simdgen/README.md +// Qt-Security score:significant reason:default #include "qsimd_x86_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86_p.h index ae834abe08..1a9a45dbb0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsimd_x86_p.h @@ -16,6 +16,7 @@ // This is a generated file. DO NOT EDIT. // Please see util/x86simdgen/README.md +// Qt-Security score:significant reason:default #ifndef QSIMD_X86_P_H #define QSIMD_X86_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qstdlibdetection.h b/local/recipes/qt/qtbase/source/src/corelib/global/qstdlibdetection.h index 64c588237f..0853d89fc2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qstdlibdetection.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qstdlibdetection.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #if 0 #pragma qt_class(QtStdLibDetection) diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qswap.h b/local/recipes/qt/qtbase/source/src/corelib/global/qswap.h index 3d533c8a95..cbf93fccfb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qswap.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qswap.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTCORE_QSWAP_H #define QTCORE_QSWAP_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.cpp index 78e50cd858..7d210da3a1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qsysinfo.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.h b/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.h index 01f6313299..d9833f042b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsysinfo.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSYSINFO_H #define QSYSINFO_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h b/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h index 87fae72451..9d7bfcf3a4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if 0 #pragma qt_class(QtSystemDetection) diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h.orig b/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h.orig new file mode 100644 index 0000000000..bb669bac33 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qsystemdetection.h.orig @@ -0,0 +1,252 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2019 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default + +#if 0 +#pragma qt_class(QtSystemDetection) +#pragma qt_sync_skip_header_check +#pragma qt_sync_stop_processing +#endif + +#ifndef QSYSTEMDETECTION_H +#define QSYSTEMDETECTION_H + +/* + The operating system, must be one of: (Q_OS_x) + + DARWIN - Any Darwin system (macOS, iOS, watchOS, tvOS) + MACOS - macOS + IOS - iOS + WATCHOS - watchOS + TVOS - tvOS + VISIONOS - visionOS + WIN32 - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008) + CYGWIN - Cygwin + SOLARIS - Sun Solaris + HPUX - HP-UX + LINUX - Linux [has variants] + FREEBSD - FreeBSD [has variants] + NETBSD - NetBSD + OPENBSD - OpenBSD + INTERIX - Interix + AIX - AIX + HURD - GNU Hurd + QNX - QNX [has variants] + QNX6 - QNX RTP 6.1 + LYNX - LynxOS + BSD4 - Any BSD 4.4 system + UNIX - Any UNIX BSD/SYSV system + ANDROID - Android platform + HAIKU - Haiku + WEBOS - LG WebOS + WASM - WebAssembly + + The following operating systems have variants: + LINUX - both Q_OS_LINUX and Q_OS_ANDROID are defined when building for Android + - only Q_OS_LINUX is defined if building for other Linux systems + MACOS - both Q_OS_BSD4 and Q_OS_IOS are defined when building for iOS + - both Q_OS_BSD4 and Q_OS_MACOS are defined when building for macOS + FREEBSD - Q_OS_FREEBSD is defined only when building for FreeBSD with a BSD userland + - Q_OS_FREEBSD_KERNEL is always defined on FreeBSD, even if the userland is from GNU +*/ + +#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__)) +# include +# define Q_OS_APPLE +# if defined(TARGET_OS_MAC) && TARGET_OS_MAC +# define Q_OS_DARWIN +# define Q_OS_BSD4 +# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +# define QT_PLATFORM_UIKIT +# if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH +# define Q_OS_WATCHOS +# elif defined(TARGET_OS_TV) && TARGET_OS_TV +# define Q_OS_TVOS +# elif defined(TARGET_OS_VISION) && TARGET_OS_VISION +# define Q_OS_VISIONOS +# else +# // TARGET_OS_IOS is only available in newer SDKs, +# // so assume any other iOS-based platform is iOS for now +# define Q_OS_IOS +# endif +# else +# // TARGET_OS_OSX is only available in newer SDKs, +# // so assume any non iOS-based platform is macOS for now +# define Q_OS_MACOS +# endif +# else +# error "Qt has not been ported to this Apple platform - see http://www.qt.io/developers" +# endif +#elif defined(__WEBOS__) +# define Q_OS_WEBOS +# define Q_OS_LINUX +#elif defined(__ANDROID__) || defined(ANDROID) +# define Q_OS_ANDROID +# define Q_OS_LINUX +#elif defined(__CYGWIN__) +# define Q_OS_CYGWIN +#elif !defined(SAG_COM) && (!defined(WINAPI_FAMILY) || WINAPI_FAMILY==WINAPI_FAMILY_DESKTOP_APP) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) +# define Q_OS_WIN32 +# define Q_OS_WIN64 +#elif !defined(SAG_COM) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) +# define Q_OS_WIN32 +#elif defined(__sun) || defined(sun) +# define Q_OS_SOLARIS +#elif defined(hpux) || defined(__hpux) +# define Q_OS_HPUX +#elif defined(__EMSCRIPTEN__) +# define Q_OS_WASM +#elif defined(__linux__) || defined(__linux) +# define Q_OS_LINUX +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +# ifndef __FreeBSD_kernel__ +# define Q_OS_FREEBSD +# endif +# define Q_OS_FREEBSD_KERNEL +# define Q_OS_BSD4 +#elif defined(__NetBSD__) +# define Q_OS_NETBSD +# define Q_OS_BSD4 +#elif defined(__OpenBSD__) +# define Q_OS_OPENBSD +# define Q_OS_BSD4 +#elif defined(__INTERIX) +# define Q_OS_INTERIX +# define Q_OS_BSD4 +#elif defined(_AIX) +# define Q_OS_AIX +#elif defined(__Lynx__) +# define Q_OS_LYNX +#elif defined(__GNU__) +# define Q_OS_HURD +#elif defined(__QNXNTO__) +# define Q_OS_QNX +#elif defined(__INTEGRITY) +# define Q_OS_INTEGRITY +#elif defined(__rtems__) +# define Q_OS_RTEMS +#elif defined(__vxworks) +# define Q_OS_VXWORKS +#elif defined(__HAIKU__) +# define Q_OS_HAIKU +#elif defined(__MAKEDEPEND__) +#else +# error "Qt has not been ported to this OS - see http://www.qt-project.org/" +#endif + +#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) +# define Q_OS_WINDOWS +# define Q_OS_WIN +// On Windows, pointers to dllimport'ed variables are not constant expressions, +// so to keep to certain initializations (like QMetaObject) constexpr, we need +// to use functions instead. +# define QT_NO_DATA_RELOCATION +#endif + +#if defined(Q_OS_WIN) +# undef Q_OS_UNIX +#elif !defined(Q_OS_UNIX) +# define Q_OS_UNIX +#endif + +// Compatibility synonyms +#ifdef Q_OS_DARWIN +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# define Q_OS_MAC // FIXME: Deprecate +# ifdef __LP64__ +# define Q_OS_DARWIN64 +# pragma clang deprecated(Q_OS_DARWIN64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead") +# define Q_OS_MAC64 +# pragma clang deprecated(Q_OS_MAC64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead") +# else +# define Q_OS_DARWIN32 +# pragma clang deprecated(Q_OS_DARWIN32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead") +# define Q_OS_MAC32 +# pragma clang deprecated(Q_OS_MAC32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead") +# endif +# ifdef Q_OS_MACOS +# define Q_OS_MACX +# pragma clang deprecated(Q_OS_MACX, "use Q_OS_MACOS instead") +# define Q_OS_OSX +# pragma clang deprecated(Q_OS_OSX, "use Q_OS_MACOS instead") +# endif +# pragma clang diagnostic pop +#endif + +#ifdef Q_OS_DARWIN +# include +# include + +# define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) \ + ((defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && macos != __MAC_NA && __MAC_OS_X_VERSION_MAX_ALLOWED >= macos) || \ + (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && ios != __IPHONE_NA && __IPHONE_OS_VERSION_MAX_ALLOWED >= ios) || \ + (defined(__TV_OS_VERSION_MAX_ALLOWED) && tvos != __TVOS_NA && __TV_OS_VERSION_MAX_ALLOWED >= tvos) || \ + (defined(__WATCH_OS_VERSION_MAX_ALLOWED) && watchos != __WATCHOS_NA && __WATCH_OS_VERSION_MAX_ALLOWED >= watchos)) + +# define QT_DARWIN_DEPLOYMENT_TARGET_BELOW(macos, ios, tvos, watchos) \ + ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && macos != __MAC_NA && __MAC_OS_X_VERSION_MIN_REQUIRED < macos) || \ + (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && ios != __IPHONE_NA && __IPHONE_OS_VERSION_MIN_REQUIRED < ios) || \ + (defined(__TV_OS_VERSION_MIN_REQUIRED) && tvos != __TVOS_NA && __TV_OS_VERSION_MIN_REQUIRED < tvos) || \ + (defined(__WATCH_OS_VERSION_MIN_REQUIRED) && watchos != __WATCHOS_NA && __WATCH_OS_VERSION_MIN_REQUIRED < watchos)) + +# define QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios) \ + QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, __TVOS_NA, __WATCHOS_NA) +# define QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos) \ + QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, __IPHONE_NA, __TVOS_NA, __WATCHOS_NA) +# define QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(ios) \ + QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, ios, __TVOS_NA, __WATCHOS_NA) +# define QT_TVOS_PLATFORM_SDK_EQUAL_OR_ABOVE(tvos) \ + QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_NA, tvos, __WATCHOS_NA) +# define QT_WATCHOS_PLATFORM_SDK_EQUAL_OR_ABOVE(watchos) \ + QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_NA, __IPHONE_NA, __TVOS_NA, watchos) + +# define QT_MACOS_IOS_DEPLOYMENT_TARGET_BELOW(macos, ios) \ + QT_DARWIN_DEPLOYMENT_TARGET_BELOW(macos, ios, __TVOS_NA, __WATCHOS_NA) +# define QT_MACOS_DEPLOYMENT_TARGET_BELOW(macos) \ + QT_DARWIN_DEPLOYMENT_TARGET_BELOW(macos, __IPHONE_NA, __TVOS_NA, __WATCHOS_NA) +# define QT_IOS_DEPLOYMENT_TARGET_BELOW(ios) \ + QT_DARWIN_DEPLOYMENT_TARGET_BELOW(__MAC_NA, ios, __TVOS_NA, __WATCHOS_NA) +# define QT_TVOS_DEPLOYMENT_TARGET_BELOW(tvos) \ + QT_DARWIN_DEPLOYMENT_TARGET_BELOW(__MAC_NA, __IPHONE_NA, tvos, __WATCHOS_NA) +# define QT_WATCHOS_DEPLOYMENT_TARGET_BELOW(watchos) \ + QT_DARWIN_DEPLOYMENT_TARGET_BELOW(__MAC_NA, __IPHONE_NA, __TVOS_NA, watchos) + +#else // !Q_OS_DARWIN + +#define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) (0) +#define QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios) (0) +#define QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos) (0) +#define QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(ios) (0) +#define QT_TVOS_PLATFORM_SDK_EQUAL_OR_ABOVE(tvos) (0) +#define QT_WATCHOS_PLATFORM_SDK_EQUAL_OR_ABOVE(watchos) (0) + +#endif // Q_OS_DARWIN + +#ifdef __LSB_VERSION__ +# if __LSB_VERSION__ < 40 +# error "This version of the Linux Standard Base is unsupported" +# endif +#ifndef QT_LINUXBASE +# define QT_LINUXBASE +#endif +#endif + +#if defined (__ELF__) +# define Q_OF_ELF +#endif +#if defined (__MACH__) && defined (__APPLE__) +# define Q_OF_MACH_O +#endif + +#if defined(__SIZEOF_INT128__) +// Compiler used in VxWorks SDK declares __SIZEOF_INT128__ but VxWorks doesn't support this type, +// so we can't rely solely on compiler here. +// MSVC STL used by MSVC and clang-cl does not support int128 +#if !defined(Q_OS_VXWORKS) && !defined(_MSC_VER) +# define QT_COMPILER_SUPPORTS_INT128 __SIZEOF_INT128__ +#endif +#endif // defined(__SIZEOF_INT128__) + +#endif // QSYSTEMDETECTION_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qt_pch.h b/local/recipes/qt/qtbase/source/src/corelib/global/qt_pch.h index 3f224cda85..083d7041df 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qt_pch.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qt_pch.h @@ -8,6 +8,7 @@ * better to define your own header. Use of this header is currently * UNSUPPORTED. */ +// Qt-Security score:significant reason:default #if defined __cplusplus diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qt_windows.h b/local/recipes/qt/qtbase/source/src/corelib/global/qt_windows.h index 5586d0b927..886d9fadf3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qt_windows.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qt_windows.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QT_WINDOWS_H #define QT_WINDOWS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelper_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelper_p.h index 1e35672612..b8dd1de47d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelper_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelper_p.h @@ -44,11 +44,28 @@ QT_BEGIN_NAMESPACE q_choose_append(m_container, lvalue, rvalue); + For all other purposes, you can use + + q_choose_copy_move(lvalue, rvalue); + + though note that this always produces an rvalue (the copy, if any, is done + inside the function). + The functions mandate (in the C++ sense) that all arguments are the same type, so they deduce each argument separately and then static_assert that they're the same. If we need std::exchange()-like mixed types later, it's easy to relax. For now, avoid being overly general. */ +template +U q_choose_copy_move(const U &lvalue, V *rvalue) +{ + static_assert(std::is_same_v, "all arguments must be of the same type"); + if (rvalue) + return std::move(*rvalue); + else + return lvalue; +} + template decltype(auto) q_choose_assign(T &var, const U &lvalue, V *rvalue) { diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelpermacros.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelpermacros.h index 2aadc55c67..3a87a7cecb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelpermacros.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtclasshelpermacros.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTCLASSHELPERMACROS_H #define QTCLASSHELPERMACROS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtconfiginclude.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtconfiginclude.h index 8e86a2c825..08d987f616 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtconfiginclude.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtconfiginclude.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 Intel Corporation // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTCONFIGINCLUDE_H #define QTCONFIGINCLUDE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtconfigmacros.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtconfigmacros.h index ba6f522bb2..2c20492f6e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtconfigmacros.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtconfigmacros.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTCONFIGMACROS_H #define QTCONFIGMACROS_H @@ -184,6 +185,16 @@ namespace QT_NAMESPACE {} # define QT_DISABLE_DEPRECATED_UP_TO QT_ENABLE_STRICT_MODE_UP_TO #endif +// +// Add new versions _here_, newest first! +// + +#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 12, 0) +# ifndef QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD +# define QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD +# endif +#endif // 6.12.0 + #if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 0, 0) # ifndef QT_NO_FOREACH # define QT_NO_FOREACH @@ -232,11 +243,10 @@ namespace QT_NAMESPACE {} # endif #endif // 6.9.0 -#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 11, 0) -# ifndef QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD -# define QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD -# endif -#endif // 6.11.0 +// +// newer versions are added newest-first at the _front_! +// + #endif // QT_ENABLE_STRICT_MODE_UP_TO #endif /* QTCONFIGMACROS_H */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal.h index b067f44952..b7a1cfd73b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if 0 #pragma qt_class(QtCoreGlobal) diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal_p.h index 89c317e2d9..31c2ec30d0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtcoreglobal_p.h @@ -2,6 +2,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTCOREGLOBAL_P_H #define QTCOREGLOBAL_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtdeprecationmarkers.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtdeprecationmarkers.h index cd29bde281..8bbbdb15e7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtdeprecationmarkers.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtdeprecationmarkers.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTDEPRECATIONMARKERS_H #define QTDEPRECATIONMARKERS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.cpp index 0126025114..7fbe588daa 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qtenvironmentvariables.h" #include "qtenvironmentvariables_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.h index 9f650d35af..026cb8451c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTENVIRONMENTVARIABLES_H #define QTENVIRONMENTVARIABLES_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables_p.h index 0c81d36db6..4854037857 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtenvironmentvariables_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2017 The Qt Company Ltd. // Copyright (C) 2015 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTENVIRONMENTVARIABLES_P_H #define QTENVIRONMENTVARIABLES_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtnoop.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtnoop.h index 83f13dfcb4..b3cd8f3162 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtnoop.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtnoop.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTNOOP_H #define QTNOOP_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtpreprocessorsupport.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtpreprocessorsupport.h index 73bbeb68b6..798e201a1b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtpreprocessorsupport.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtpreprocessorsupport.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTPREPROCESSORSUPPORT_H #define QTPREPROCESSORSUPPORT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtrace_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtrace_p.h index f4e39ffe2b..4b8505c492 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtrace_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtrace_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTRACE_P_H #define QTRACE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtresource.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtresource.h index 535903aac0..728e2e568b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtresource.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtresource.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTRESOURCE_H #define QTRESOURCE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtsymbolmacros.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtsymbolmacros.h index 18cdc85f72..cab9447818 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtsymbolmacros.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtsymbolmacros.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef QTSYMBOLMACROS_H #define QTSYMBOLMACROS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qttranslation.h b/local/recipes/qt/qtbase/source/src/corelib/global/qttranslation.h index 1d1609481b..4ddb4e75f7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qttranslation.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qttranslation.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTTRANSLATION_H #define QTTRANSLATION_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qttypetraits.h b/local/recipes/qt/qtbase/source/src/corelib/global/qttypetraits.h index a81ac5baeb..3b5853e1a9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qttypetraits.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qttypetraits.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTTYPETRAITS_H #define QTTYPETRAITS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtversion.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtversion.h index 775f2479a9..aa5e0aa498 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtversion.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtversion.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QTVERSION_H #define QTVERSION_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtversionchecks.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtversionchecks.h index 86fc094f4e..aca235f457 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtversionchecks.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtversionchecks.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTVERSIONCHECKS_H #define QTVERSIONCHECKS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtypeinfo.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtypeinfo.h index 6451c19d35..37cb3ed54d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtypeinfo.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtypeinfo.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTYPEINFO_H #define QTYPEINFO_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.cpp index 6b79c1fa9e..4edbc63c0d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qtypes.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h index c603ba7de4..9697463685 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qtypes.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTYPES_H #define QTYPES_H @@ -177,22 +178,6 @@ static_assert(std::is_signed_v, #endif // QT_SUPPORTS_INT128 #ifndef __cplusplus -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef static_assert -#define static_assert _Static_assert -#endif // In C++ mode, we define below using QIntegerForSize template static_assert(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions"); typedef ptrdiff_t qptrdiff; diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.cpp b/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.cpp index a8191869cc..e05e90fb47 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qversiontagging.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.h b/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.h index fa2dd23728..df38b255a3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qversiontagging.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #if !defined(QVERSIONTAGGING_H) #define QVERSIONTAGGING_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qvolatile_p.h b/local/recipes/qt/qtbase/source/src/corelib/global/qvolatile_p.h index 36787ecd87..5498872f83 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qvolatile_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qvolatile_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QVOLATILE_P_H #define QVOLATILE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qxpfunctional.h b/local/recipes/qt/qtbase/source/src/corelib/global/qxpfunctional.h index 2dd7de669d..28121d3649 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qxpfunctional.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qxpfunctional.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QXPFUNCTIONAL_H #define QXPFUNCTIONAL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/global/qxptype_traits.h b/local/recipes/qt/qtbase/source/src/corelib/global/qxptype_traits.h index dafba5112a..502cc4dac7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/global/qxptype_traits.h +++ b/local/recipes/qt/qtbase/source/src/corelib/global/qxptype_traits.h @@ -1,6 +1,7 @@ // Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz , Giuseppe D'Angelo // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QXPTYPE_TRAITS_H #define QXPTYPE_TRAITS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/forkfd_qt.c b/local/recipes/qt/qtbase/source/src/corelib/io/forkfd_qt.c index 9669af8eee..de564195d7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/forkfd_qt.c +++ b/local/recipes/qt/qtbase/source/src/corelib/io/forkfd_qt.c @@ -12,5 +12,13 @@ # define NDEBUG #endif +// Redox: declare struct rusage at file scope BEFORE forkfd.h, whose +// forkfd_wait4() prototype takes a struct rusage*. Without a prior file-scope +// declaration the struct is implicitly declared in prototype scope, so the +// header prototype and the definition in forkfd.c (which includes +// ) get incompatible struct rusage types -> "conflicting types +// for 'forkfd_wait4'". (6.11.0's qglobal.h pulled this in transitively; 6.11.1 +// does not.) +#include #include #include "../../3rdparty/forkfd/forkfd.c" diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qdirentryinfo_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qdirentryinfo_p.h index c729fb814b..72f6c85246 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qdirentryinfo_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qdirentryinfo_p.h @@ -22,37 +22,109 @@ QT_BEGIN_NAMESPACE +namespace QDirEntryInfoPrivate { +template +struct overloaded : Ts... { using Ts::operator()...; }; +template +overloaded(Ts...) -> overloaded; +}; + class QDirEntryInfo { - const QFileSystemMetaData &ensureFilled(QFileSystemMetaData::MetaDataFlags what) + template + auto query( + QueryNative &&queryNative, QueryFileInfo &&queryFileInfo, QueryIterator &&queryIterator) { - if (!metaData.hasFlags(what)) - QFileSystemEngine::fillMetaData(entry, metaData, what); - return metaData; + return std::visit(QDirEntryInfoPrivate::overloaded { + std::forward(queryNative), + std::forward(queryFileInfo), + [&](const Iterator &iterator) { return queryIterator(iterator.iterator); } + }, content); + } + + template + auto query(QueryNative &&queryNative, const QueryFileInfo &queryFileInfo) + { + return std::visit(QDirEntryInfoPrivate::overloaded { + std::forward(queryNative), + [&](Iterator &iterator) { return queryFileInfo(iterator.ensureFileInfo()); }, + queryFileInfo, + }, content); } public: + QDirEntryInfo() = default; + + explicit QDirEntryInfo(const QAbstractFileEngineIterator *iterator) + : content(Iterator {iterator, {}}) + { + } + + explicit QDirEntryInfo(QFileSystemEntry &&e, QFileSystemMetaData &&md) + : content(Native { std::move(e), std::move(md) }) + { + } + + explicit QDirEntryInfo(QFileInfo &&info) + : content(std::move(info)) + { + } + const QFileInfo &fileInfo() { - if (!fileInfoOpt) { - fileInfoOpt.emplace(new QFileInfoPrivate(entry, metaData)); - metaData.clear(); - } - return *fileInfoOpt; + return std::visit(QDirEntryInfoPrivate::overloaded { + [](Iterator &iterator) -> const QFileInfo & { return iterator.ensureFileInfo(); }, + [this](const Native &native) -> const QFileInfo & { + content = QFileInfo(new QFileInfoPrivate(native.entry, native.metaData)); + return std::get(content); + }, + [](const QFileInfo &fileInfo) -> const QFileInfo & { return fileInfo; } + }, content); } QString fileName() - { return fileInfoOpt ? fileInfoOpt->fileName() : entry.fileName(); } + { + return query( + [](const Native &native) { return native.entry.fileName(); }, + [](const QFileInfo &info) { return info.fileName(); }, + [](const QAbstractFileEngineIterator *it) { return it->currentFileName(); }); + } + QString baseName() - { return fileInfoOpt ? fileInfoOpt->baseName() : entry.baseName(); } - QString completeBaseName() const - { return fileInfoOpt ? fileInfoOpt->completeBaseName() : entry.completeBaseName(); } - QString suffix() const - { return fileInfoOpt ? fileInfoOpt->suffix() : entry.suffix(); } - QString completeSuffix() const - { return fileInfoOpt ? fileInfoOpt->completeSuffix() : entry.completeSuffix(); } + { + return query( + [](const Native &native) { return native.entry.baseName(); }, + [](const QFileInfo &info) { return info.baseName(); }); + } + + QString completeBaseName() + { + return query( + [](const Native &native) { return native.entry.completeBaseName(); }, + [](const QFileInfo &info) { return info.completeBaseName(); }); + } + + QString suffix() + { + return query( + [](const Native &native) { return native.entry.suffix(); }, + [](const QFileInfo &info) { return info.suffix(); }); + } + + QString completeSuffix() + { + return query( + [](const Native &native) { return native.entry.completeSuffix(); }, + [](const QFileInfo &info) { return info.completeSuffix(); }); + } + QString filePath() - { return fileInfoOpt ? fileInfoOpt->filePath() : entry.filePath(); } + { + return query( + [](const Native &native) { return native.entry.filePath(); }, + [](const QFileInfo &info) { return info.filePath(); }, + [](const QAbstractFileEngineIterator *it) { return it->currentFilePath(); }); + } QString bundleName() { return fileInfo().bundleName(); } @@ -74,66 +146,76 @@ public: bool isDir() { - if (fileInfoOpt) - return fileInfoOpt->isDir(); - - return ensureFilled(QFileSystemMetaData::DirectoryType).isDirectory(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::DirectoryType).isDirectory(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isDir(); }); } bool isFile() { - if (fileInfoOpt) - return fileInfoOpt->isFile(); - - return ensureFilled(QFileSystemMetaData::FileType).isFile(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::FileType).isFile(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isFile(); }); } bool isSymLink() { - if (fileInfoOpt) - return fileInfoOpt->isSymLink(); - - return ensureFilled(QFileSystemMetaData::LegacyLinkType).isLegacyLink(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::LegacyLinkType).isLegacyLink(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isSymLink(); }); } bool isSymbolicLink() { - if (fileInfoOpt) - return fileInfoOpt->isSymbolicLink(); - - return ensureFilled(QFileSystemMetaData::LinkType).isLink(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::LinkType).isLink(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isSymbolicLink(); }); } bool exists() { - if (fileInfoOpt) - return fileInfoOpt->exists(); - - return ensureFilled(QFileSystemMetaData::ExistsAttribute).exists(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::ExistsAttribute).exists(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.exists(); }); } bool isHidden() { - if (fileInfoOpt) - return fileInfoOpt->isHidden(); - - return ensureFilled(QFileSystemMetaData::HiddenAttribute).isHidden(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::HiddenAttribute).isHidden(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isHidden(); }); } bool isReadable() { - if (fileInfoOpt) - return fileInfoOpt->isReadable(); - - return ensureFilled(QFileSystemMetaData::UserReadPermission).isReadable(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::UserReadPermission).isReadable(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isReadable(); }); } bool isWritable() { - if (fileInfoOpt) - return fileInfoOpt->isWritable(); - - return ensureFilled(QFileSystemMetaData::UserWritePermission).isWritable(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::UserWritePermission).isWritable(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isWritable(); }); } bool isExecutable() { - if (fileInfoOpt) - return fileInfoOpt->isExecutable(); - - return ensureFilled(QFileSystemMetaData::UserExecutePermission).isExecutable(); + return query( + [](Native &native) { + return native.ensureFilled(QFileSystemMetaData::UserExecutePermission) + .isExecutable(); + }, + [](const QFileInfo &fileInfo) {return fileInfo.isExecutable(); }); } qint64 size() { return fileInfo().size(); } @@ -147,9 +229,35 @@ private: friend class QDirListingPrivate; friend class QDirListing; - QFileSystemEntry entry; - QFileSystemMetaData metaData; - std::optional fileInfoOpt = std::nullopt; + struct Iterator + { + // The data we can query from both the QFileInfo and the iterator is cheaper to retrieve + // from the iterator. Therefore, keep the iterator around even if we create a the QFileInfo. + const QAbstractFileEngineIterator *iterator = nullptr; + std::optional fileInfo; + + const QFileInfo &ensureFileInfo() + { + if (!fileInfo.has_value()) + fileInfo = iterator->currentFileInfo(); + return *fileInfo; + } + }; + + struct Native + { + QFileSystemEntry entry; + QFileSystemMetaData metaData; + + const QFileSystemMetaData &ensureFilled(QFileSystemMetaData::MetaDataFlag what) + { + if (!metaData.hasFlags(what)) + QFileSystemEngine::fillMetaData(entry, metaData, what); + return metaData; + } + }; + + std::variant content; }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qdirlisting.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qdirlisting.cpp index ec86fba0af..5207d2a8c0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qdirlisting.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qdirlisting.cpp @@ -213,6 +213,12 @@ public: // Loop protection QDuplicateTracker visitedLinks; + +private: + bool matchesFilters(const QFileInfo &fileInfo) const; + bool matchesFilters(QDirEntryInfo::Iterator &iterator) const; + bool matchesFilters(const QFileInfo &fileInfo, const QString &fileName) const; + bool matchesFilters(QDirEntryInfo::Native &native) const; }; void QDirListingPrivate::init() @@ -229,8 +235,8 @@ void QDirListingPrivate::init() nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs)); #endif - engine = QFileSystemEngine::createLegacyEngine(initialEntryInfo.entry, - initialEntryInfo.metaData); + QDirEntryInfo::Native &native = std::get(initialEntryInfo.content); + engine = QFileSystemEngine::createLegacyEngine(native.entry, native.metaData); } /*! @@ -275,12 +281,11 @@ void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo) } } else { #ifndef QT_NO_FILESYSTEMITERATOR - QFileSystemEntry *fentry = nullptr; - if (entryInfo.fileInfoOpt) - fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry; - else - fentry = &entryInfo.entry; - nativeIterators.push(std::make_unique(*fentry, iteratorFlags)); + nativeIterators.push(std::make_unique( + entryInfo.query( + [](const QDirEntryInfo::Native &native) { return native.entry; }, + [](const QFileInfo &fileInfo) { return fileInfo.d_ptr->fileEntry; }), + iteratorFlags)); #else qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!"); #endif @@ -314,8 +319,7 @@ void QDirListingPrivate::advance() // Find the next valid iterator that matches the filters. // Always use top() because entryMatches() may modify `fileEngineIterators`! while (fileEngineIterators.top()->advance()) { - QDirEntryInfo entryInfo; - entryInfo.fileInfoOpt = fileEngineIterators.top()->currentFileInfo(); + QDirEntryInfo entryInfo{fileEngineIterators.top().get()}; if (entryMatches(entryInfo)) { currentEntryInfo = std::move(entryInfo); return; @@ -326,16 +330,19 @@ void QDirListingPrivate::advance() } } else { #ifndef QT_NO_FILESYSTEMITERATOR - QDirEntryInfo entryInfo; + QFileSystemEntry fileEntry; + QFileSystemMetaData metaData; while (!nativeIterators.empty()) { // Find the next valid iterator that matches the filters. // Always use top() because entryMatches() may modify `nativeIterators`! - while (nativeIterators.top()->advance(entryInfo.entry, entryInfo.metaData)) { - if (entryMatches(entryInfo)) { + while (nativeIterators.top()->advance(fileEntry, metaData)) { + if (QDirEntryInfo entryInfo{ std::move(fileEntry), std::move(metaData) }; + entryMatches(entryInfo)) { currentEntryInfo = std::move(entryInfo); return; } - entryInfo = {}; + fileEntry = {}; + metaData = {}; } nativeIterators.pop(); @@ -376,25 +383,19 @@ void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo) pushDirectory(entryInfo); } -/*! - \internal - - This function returns \c true if the current entry matches the filters - (i.e., the current entry will be returned as part of the directory - iteration); otherwise, \c false is returned. -*/ -bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const +bool QDirListingPrivate::matchesFilters(QDirEntryInfo::Native &native) const { using F = QDirListing::IteratorFlag; + using M = QFileSystemMetaData; - const QString &fileName = entryInfo.fileName(); + const QString fileName = native.entry.fileName(); if (fileName.isEmpty()) return false; // name filter #if QT_CONFIG(regularexpression) const bool skipNameFilters = iteratorFlags.testAnyFlags(F::NoNameFiltersForDirs) - && entryInfo.isDir(); + && native.ensureFilled(M::DirectoryType).isDirectory(); if (!skipNameFilters) { if (!regexMatchesName(fileName)) return false; @@ -404,37 +405,151 @@ bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const if (isDotOrDotDot(fileName)) return iteratorFlags.testFlags(F::IncludeDotAndDotDot); - if (!iteratorFlags.testAnyFlag(F::IncludeHidden) && entryInfo.isHidden()) + if (!iteratorFlags.testAnyFlag(F::IncludeHidden) + && native.ensureFilled(M::HiddenAttribute).isHidden()) { return false; + } - const bool includeBrokenSymlinks = iteratorFlags.testAnyFlags(F::IncludeBrokenSymlinks); - if (includeBrokenSymlinks && entryInfo.isSymLink() && !entryInfo.exists()) + if (iteratorFlags.testAnyFlags(F::IncludeBrokenSymlinks) + && native.ensureFilled(M::LegacyLinkType).isLegacyLink() + && !native.ensureFilled(M::ExistsAttribute).exists()) { return true; + } if (iteratorFlags.testFlag(F::ResolveSymlinks)) { - if (entryInfo.isSymLink() && !entryInfo.exists()) + if (native.ensureFilled(M::LegacyLinkType).isLegacyLink() + && !native.ensureFilled(M::ExistsAttribute).exists()) { return false; // Exclude broken symlinks; anything else will be filtered below + } } else { constexpr auto f = F::ExcludeFiles | F::ExcludeDirs | F::ExcludeOther; const bool filterByTargetType = iteratorFlags.testAnyFlags(f); - if (filterByTargetType && entryInfo.isSymLink()) + if (filterByTargetType && native.ensureFilled(M::LegacyLinkType).isLegacyLink()) return false; } if (iteratorFlags.testAnyFlag(F::ExcludeOther) - && !entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink()) { + && !native.ensureFilled(M::FileType).isFile() + && !native.ensureFilled(M::DirectoryType).isDirectory() + && !native.ensureFilled(M::LegacyLinkType).isLegacyLink()) { return false; } - if (iteratorFlags.testAnyFlags(F::ExcludeDirs) && entryInfo.isDir()) + if (iteratorFlags.testAnyFlags(F::ExcludeDirs) + && native.ensureFilled(M::DirectoryType).isDirectory()) { return false; + } - if (iteratorFlags.testAnyFlags(F::ExcludeFiles) && entryInfo.isFile()) + if (iteratorFlags.testAnyFlags(F::ExcludeFiles) && native.ensureFilled(M::FileType).isFile()) return false; return true; } +bool QDirListingPrivate::matchesFilters(const QFileInfo &fileInfo, const QString &fileName) const +{ + using F = QDirListing::IteratorFlag; + + Q_ASSERT(!fileName.isEmpty()); + + // name filter +#if QT_CONFIG(regularexpression) + const bool skipNameFilters = iteratorFlags.testFlag(F::NoNameFiltersForDirs) + && fileInfo.isDir(); + if (!skipNameFilters) { + if (!regexMatchesName(fileName)) + return false; + } +#endif // QT_CONFIG(regularexpression) + + if (isDotOrDotDot(fileName)) + return iteratorFlags.testFlag(F::IncludeDotAndDotDot); + + if (!iteratorFlags.testFlag(F::IncludeHidden) && fileInfo.isHidden()) + return false; + + const bool includeBrokenSymlinks = iteratorFlags.testAnyFlags(F::IncludeBrokenSymlinks); + if (includeBrokenSymlinks && fileInfo.isSymLink() && !fileInfo.exists()) + return true; + + if (iteratorFlags.testFlag(F::ResolveSymlinks)) { + if (fileInfo.isSymLink() && !fileInfo.exists()) + return false; // Exclude broken symlinks; anything else will be filtered below + } else { + constexpr auto f = F::ExcludeFiles | F::ExcludeDirs | F::ExcludeOther; + const bool filterByTargetType = iteratorFlags.testAnyFlags(f); + if (filterByTargetType && fileInfo.isSymLink()) + return false; + } + + if (iteratorFlags.testFlag(F::ExcludeOther) + && !fileInfo.isFile() && !fileInfo.isDir() && !fileInfo.isSymLink()) { + return false; + } + + if (iteratorFlags.testFlag(F::ExcludeDirs) && fileInfo.isDir()) + return false; + + if (iteratorFlags.testFlag(F::ExcludeFiles) && fileInfo.isFile()) + return false; + + return true; +} + +bool QDirListingPrivate::matchesFilters(QDirEntryInfo::Iterator &iterator) const +{ + using F = QDirListing::IteratorFlag; + + const QString fileName = iterator.iterator->currentFileName(); + if (fileName.isEmpty()) + return false; + + // Fast path that doesn't require conversion to QFileInfo + if (iteratorFlags.testFlag(F::IncludeHidden) + && !iteratorFlags.testAnyFlags( + F::NoNameFiltersForDirs | + F::IncludeBrokenSymlinks | + F::ResolveSymlinks | + F::ExcludeFiles | + F::ExcludeDirs | + F::ExcludeOther)) { + +#if QT_CONFIG(regularexpression) + if (!regexMatchesName(fileName)) + return false; +#endif + if (isDotOrDotDot(fileName)) + return iteratorFlags.testFlags(F::IncludeDotAndDotDot); + + return true; + } + + // Conversion to QFileInfo can be expensife, but now we need to do it. + return matchesFilters(iterator.ensureFileInfo(), fileName); +} + +bool QDirListingPrivate::matchesFilters(const QFileInfo &fileInfo) const +{ + const QString fileName = fileInfo.fileName(); + return !fileName.isEmpty() && matchesFilters(fileInfo, fileName); +} + +/*! + \internal + + This function returns \c true if the current entry matches the filters + (i.e., the current entry will be returned as part of the directory + iteration); otherwise, \c false is returned. +*/ +bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const +{ + return std::visit(QDirEntryInfoPrivate::overloaded { + [this](QDirEntryInfo::Native &native) { return matchesFilters(native); }, + [this](const QFileInfo &fileInfo) { return matchesFilters(fileInfo); }, + [this](QDirEntryInfo::Iterator &iterator) { return matchesFilters(iterator); } + }, entryInfo.content); +} + bool QDirListingPrivate::hasIterators() const { if (engine) @@ -460,7 +575,7 @@ bool QDirListingPrivate::hasIterators() const QDirListing::QDirListing(const QString &path, IteratorFlags flags) : d(new QDirListingPrivate) { - d->initialEntryInfo.entry = QFileSystemEntry(path); + d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} }; d->iteratorFlags = flags; d->init(); } @@ -491,7 +606,7 @@ QDirListing::QDirListing(const QString &path, IteratorFlags flags) QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, IteratorFlags flags) : d(new QDirListingPrivate) { - d->initialEntryInfo.entry = QFileSystemEntry(path); + d->initialEntryInfo.content = QDirEntryInfo::Native { QFileSystemEntry(path), {} }; d->nameFilters = nameFilters; d->iteratorFlags = flags; d->init(); diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfile.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qfile.cpp index 3707f028ee..b9a95d04cf 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfile.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfile.cpp @@ -816,6 +816,7 @@ bool QFilePrivate::copy(const QString &newName) while (r == QAbstractFileEngine::TriStateResult::NotSupported) { // OS couldn't do it, so do a block-level copy + Q_DECL_UNINITIALIZED char block[4096]; qint64 in = q->read(block, sizeof(block)); if (in == 0) diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice.cpp index ee6a185965..9387c7b68f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice.cpp @@ -39,10 +39,10 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err) errorString.clear(); } -void QFileDevicePrivate::setError(QFileDevice::FileError err, const QString &errStr) +void QFileDevicePrivate::setError(QFileDevice::FileError err, QString errStr) { error = err; - errorString = errStr; + errorString = std::move(errStr); } void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum) diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice_p.h index 51df8966bf..c433e0ffe8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfiledevice_p.h @@ -55,7 +55,7 @@ protected: bool putCharHelper(char c) override; void setError(QFileDevice::FileError err); - void setError(QFileDevice::FileError err, const QString &errorString); + void setError(QFileDevice::FileError err, QString errorString); void setError(QFileDevice::FileError err, int errNum); mutable std::unique_ptr fileEngine; diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_p.h index a724fd6b0a..66d8f7b578 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_p.h @@ -26,10 +26,6 @@ #include #include -#if !defined(Q_OS_WIN) -#include -#endif - #include QT_BEGIN_NAMESPACE @@ -64,7 +60,6 @@ private: QT_DIRENT *dirEntry = nullptr; int lastError = 0; - QStringDecoder toUtf16; #endif Q_DISABLE_COPY_MOVE(QFileSystemIterator) diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_unix.cpp index 712b942756..4094a6f9f3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemiterator_unix.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include @@ -21,8 +23,7 @@ QT_BEGIN_NAMESPACE libraries to iterate over the directory represented by \a entry. */ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry) - : dirPath(entry.filePath()), - toUtf16(QStringDecoder::Utf8) + : dirPath(entry.filePath()) { dir.reset(QT_OPENDIR(entry.nativeFilePath().constData())); if (!dir) { @@ -75,6 +76,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa QByteArrayView name(dirEntry->d_name, strlen(dirEntry->d_name)); // name.size() is sufficient here, see QUtf8::convertToUnicode() for details QVarLengthArray buffer(name.size()); + QStringDecoder toUtf16(QStringDecoder::Utf8); auto *end = toUtf16.appendToBuffer(buffer.data(), name); buffer.resize(end - buffer.constData()); if (!toUtf16.hasError()) { diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents.mm b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents.mm index 7938c30281..0cbb808471 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents.mm +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents.mm @@ -26,6 +26,14 @@ QT_BEGIN_NAMESPACE +static bool isSameTimestampAndMode(const QT_STATBUF &statbuff, + const QFseventsFileSystemWatcherEngine::Info &info) +{ + const timespec ts = statbuff.st_ctimespec; + return (ts.tv_sec == info.ctime.tv_sec && ts.tv_nsec == info.ctime.tv_nsec) + && statbuff.st_mode == info.mode; +} + static void callBackFunction(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, @@ -52,7 +60,7 @@ bool QFseventsFileSystemWatcherEngine::checkDir(DirsByName::iterator &it) needsRestart |= derefPath(info.watchedPath); emit emitDirectoryChanged(info.origPath, true); it = watchingState.watchedDirectories.erase(it); - } else if (st.st_ctimespec != info.ctime || st.st_mode != info.mode) { + } else if (!isSameTimestampAndMode(st, info)) { info.ctime = st.st_ctimespec; info.mode = st.st_mode; emit emitDirectoryChanged(info.origPath, false); @@ -67,7 +75,7 @@ bool QFseventsFileSystemWatcherEngine::checkDir(DirsByName::iterator &it) dirChanged = true; i = entries.erase(i); } else { - if (i->ctime != st.st_ctimespec || i->mode != st.st_mode) { + if (!isSameTimestampAndMode(st, i.value())) { // entry changed dirChanged = true; i->ctime = st.st_ctimespec; @@ -131,7 +139,7 @@ bool QFseventsFileSystemWatcherEngine::rescanFiles(InfoByName &filesInPath) emit emitFileChanged(it.value().origPath, true); it = filesInPath.erase(it); continue; - } else if (st.st_ctimespec != it->ctime || st.st_mode != it->mode) { + } else if (!isSameTimestampAndMode(st, it.value())) { it->ctime = st.st_ctimespec; it->mode = st.st_mode; emit emitFileChanged(it.value().origPath, false); diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents_p.h index 2fc95a9993..324b969cee 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfilesystemwatcher_fsevents_p.h @@ -53,7 +53,7 @@ private Q_SLOTS: void doEmitDirectoryChanged(const QString &path, bool removed); bool restartStream(); -private: +public: struct Info { QString origPath; timespec ctime; @@ -73,6 +73,8 @@ private: , watchedPath(watchedPath) {} }; + +private: typedef QHash InfoByName; typedef QHash FilesByPath; struct DirInfo { diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_p.h index 8ad673bf0b..9a54b7554b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_p.h @@ -215,6 +215,41 @@ public: // ReadOnly by itself never creates. return (openMode & QFile::WriteOnly) && !(openMode & QFile::ExistingOnly); } + +#if defined(Q_OS_UNIX) + /*! + \internal + + Returns the stdio open flags corresponding to a QIODevice::OpenMode. + */ + static int openModeToOpenFlags(QIODevice::OpenMode mode) + { + int oflags = QT_OPEN_RDONLY; +# ifdef QT_LARGEFILE_SUPPORT + oflags |= QT_OPEN_LARGEFILE; +# endif + + if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) + oflags = QT_OPEN_RDWR; + else if (mode & QIODevice::WriteOnly) + oflags = QT_OPEN_WRONLY; + + if (openModeCanCreate(mode)) + oflags |= QT_OPEN_CREAT; + + if (mode & QIODevice::Truncate) + oflags |= QT_OPEN_TRUNC; + + if (mode & QIODevice::Append) + oflags |= QT_OPEN_APPEND; + + if (mode & QIODevice::NewOnly) + oflags |= QT_OPEN_EXCL; + + return oflags; + } +#endif // Q_OS_UNIX + protected: QFSFileEnginePrivate(QAbstractFileEngine *q); diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_unix.cpp index abf5a0c7db..0f29299816 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qfsfileengine_unix.cpp @@ -28,38 +28,6 @@ QT_BEGIN_NAMESPACE -/*! - \internal - - Returns the stdio open flags corresponding to a QIODevice::OpenMode. -*/ -static inline int openModeToOpenFlags(QIODevice::OpenMode mode) -{ - int oflags = QT_OPEN_RDONLY; -#ifdef QT_LARGEFILE_SUPPORT - oflags |= QT_OPEN_LARGEFILE; -#endif - - if ((mode & QFile::ReadWrite) == QFile::ReadWrite) - oflags = QT_OPEN_RDWR; - else if (mode & QFile::WriteOnly) - oflags = QT_OPEN_WRONLY; - - if (QFSFileEnginePrivate::openModeCanCreate(mode)) - oflags |= QT_OPEN_CREAT; - - if (mode & QFile::Truncate) - oflags |= QT_OPEN_TRUNC; - - if (mode & QFile::Append) - oflags |= QT_OPEN_APPEND; - - if (mode & QFile::NewOnly) - oflags |= QT_OPEN_EXCL; - - return oflags; -} - static inline QString msgOpenDirectory() { const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory"); diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qioring.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qioring.cpp index 86de7efed9..865297c48c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qioring.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qioring.cpp @@ -118,7 +118,7 @@ QIORing::ReadWriteStatus QIORing::handleReadCompletion(size_t value, QSpan(voidExtra)) { - const qsizetype bytesRead = q26::saturate_cast(value); + const qsizetype bytesRead = q26::saturating_cast(value); qCDebug(lcQIORing) << "Partial read of" << bytesRead << "bytes completed"; extra->totalProcessed = setResultFn(bytesRead); // [0/1] Add the number of bytes processed to the spanOffset - we use this to test how many @@ -138,7 +138,7 @@ QIORing::ReadWriteStatus QIORing::handleReadCompletion(size_t value, QSpan(value)); + setResultFn(q26::saturating_cast(value)); return ReadWriteStatus::Finished; } @@ -147,7 +147,7 @@ QIORing::ReadWriteStatus QIORing::handleWriteCompletion(size_t value, void *voidExtra, SetResultFn setResultFn) { if (auto *extra = static_cast(voidExtra)) { - const qsizetype bytesWritten = q26::saturate_cast(value); + const qsizetype bytesWritten = q26::saturating_cast(value); qCDebug(lcQIORing) << "Partial write of" << bytesWritten << "bytes completed"; extra->totalProcessed = setResultFn(bytesWritten); // [0/1] Add the number of bytes processed to the spanOffset - we use this to test how many @@ -167,7 +167,7 @@ QIORing::ReadWriteStatus QIORing::handleWriteCompletion(size_t value, } return ReadWriteStatus::MoreToDo; } - setResultFn(q26::saturate_cast(value)); + setResultFn(q26::saturating_cast(value)); return ReadWriteStatus::Finished; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qioring_linux.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qioring_linux.cpp index a28dbb7fc5..ad758007a9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qioring_linux.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qioring_linux.cpp @@ -10,6 +10,7 @@ QT_REQUIRE_CONFIG(liburing); #include #include #include +#include #include #include @@ -459,35 +460,6 @@ static void prepareFileReadWrite(io_uring_sqe *sqe, const QIORingRequestOffsetFd sqe->addr = quint64(address); } -// @todo: stolen from qfsfileengine_unix.cpp -static inline int openModeToOpenFlags(QIODevice::OpenMode mode) -{ - int oflags = QT_OPEN_RDONLY; -#ifdef QT_LARGEFILE_SUPPORT - oflags |= QT_OPEN_LARGEFILE; -#endif - - if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) - oflags = QT_OPEN_RDWR; - else if (mode & QIODevice::WriteOnly) - oflags = QT_OPEN_WRONLY; - - if ((mode & QIODevice::WriteOnly) - && !(mode & QIODevice::ExistingOnly)) // QFSFileEnginePrivate::openModeCanCreate(mode)) - oflags |= QT_OPEN_CREAT; - - if (mode & QIODevice::Truncate) - oflags |= QT_OPEN_TRUNC; - - if (mode & QIODevice::Append) - oflags |= QT_OPEN_APPEND; - - if (mode & QIODevice::NewOnly) - oflags |= QT_OPEN_EXCL; - - return oflags; -} - /*! \internal Because vectored operations are also affected by the maximum size @@ -598,7 +570,7 @@ auto QIORing::prepareRequest(io_uring_sqe *sqe, GenericRequestType &request) -> *openRequest = request.template requestData(); sqe->fd = AT_FDCWD; // Could also support proper openat semantics sqe->addr = reinterpret_cast(openRequest->path.native().c_str()); - sqe->open_flags = openModeToOpenFlags(openRequest->flags); + sqe->open_flags = QFSFileEnginePrivate::openModeToOpenFlags(openRequest->flags); auto &mode = sqe->len; mode = 0666; // With an explicit API we can use QtPrivate::toMode_t() for this break; diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qioring_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qioring_win.cpp index a2b6eda5d1..7932bab544 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qioring_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qioring_win.cpp @@ -83,7 +83,7 @@ static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan(destination.size()); + const auto maxSize = q26::saturating_cast(destination.size()); Q_ASSERT(maxSize == destination.size()); const auto *apiTable = QtPrivate::getApiTable(); Q_ASSERT(apiTable); // If we got this far it needs to be here @@ -97,7 +97,7 @@ static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan(source.data())); - const auto maxSize = q26::saturate_cast(source.size()); + const auto maxSize = q26::saturating_cast(source.size()); Q_ASSERT(maxSize == source.size()); const auto *apiTable = QtPrivate::getApiTable(); Q_ASSERT(apiTable); // If we got this far it needs to be here @@ -300,7 +300,7 @@ bool QIORing::waitForCompletions(QDeadlineTimer deadline) if (deadline.isForever()) { timeout = INFINITE; } else { - timeout = q26::saturate_cast(deadline.remainingTime()); + timeout = q26::saturating_cast(deadline.remainingTime()); if (timeout == INFINITE) --timeout; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qprocess_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qprocess_unix.cpp index c6f8d96a20..2642d5317c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qprocess_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qprocess_unix.cpp @@ -200,7 +200,7 @@ static constexpr int FakeErrnoForThrow = std::numeric_limits::max(); static QString errorMessageForSyscall(QUtf8StringView fnName, int errnoCode = -1) { QString msg = qt_error_string(errnoCode); - return QProcess::tr("Child process set up failed: %1: %2").arg(fnName, std::move(msg)); + return QProcess::tr("Child process set up failed: %1: %2").arg(fnName, msg); } static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead) diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_darwin.mm index 80c1affa64..8d1cf465b7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_darwin.mm +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_darwin.mm @@ -540,29 +540,6 @@ void QRandomAccessAsyncFileNativeBackend::executeFlush(OperationInfo &opInfo) }); } -// stolen from qfsfileengine_unix.cpp -static inline int openModeToOpenFlags(QIODevice::OpenMode mode) -{ - int oflags = QT_OPEN_RDONLY; -#ifdef QT_LARGEFILE_SUPPORT - oflags |= QT_OPEN_LARGEFILE; -#endif - if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite) - oflags = QT_OPEN_RDWR; - else if (mode & QIODevice::WriteOnly) - oflags = QT_OPEN_WRONLY; - if ((mode & QIODevice::WriteOnly) - && !(mode & QIODevice::ExistingOnly)) // QFSFileEnginePrivate::openModeCanCreate(mode)) - oflags |= QT_OPEN_CREAT; - if (mode & QIODevice::Truncate) - oflags |= QT_OPEN_TRUNC; - if (mode & QIODevice::Append) - oflags |= QT_OPEN_APPEND; - if (mode & QIODevice::NewOnly) - oflags |= QT_OPEN_EXCL; - return oflags; -} - void QRandomAccessAsyncFileNativeBackend::executeOpen(OperationInfo &opInfo) { if (m_fileState != FileState::OpenPending) { @@ -572,7 +549,7 @@ void QRandomAccessAsyncFileNativeBackend::executeOpen(OperationInfo &opInfo) const QByteArray nativeName = QFile::encodeName(QDir::toNativeSeparators(m_filePath)); - int openFlags = openModeToOpenFlags(m_openMode); + int openFlags = QFSFileEnginePrivate::openModeToOpenFlags(m_openMode); openFlags |= O_NONBLOCK; auto sharedThis = this; diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_qioring.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_qioring.cpp index 8e1145325d..5bf5d4529d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_qioring.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qrandomaccessasyncfile_qioring.cpp @@ -155,7 +155,7 @@ qint64 QRandomAccessAsyncFileNativeBackend::size() const Q_UNUSED(err); finalSize = -1; } else if (const auto *res = std::get_if>(&request.result)) { - finalSize = q26::saturate_cast(res->size); + finalSize = q26::saturating_cast(res->size); } }); auto *handle = m_ioring->queueRequest(std::move(statRequest)); diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qresource.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qresource.cpp index 5f692c7c43..eb3898159a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qresource.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qresource.cpp @@ -123,6 +123,7 @@ private: inline int findOffset(int node) const { return node * (14 + (version >= 0x02 ? 8 : 0)); } //sizeof each tree element uint hash(int node) const; QString name(int node) const; + bool nameMatches(int node, QStringView other) const; short flags(int node) const; public: mutable QAtomicInt ref; @@ -789,6 +790,27 @@ inline QString QResourceRoot::name(int node) const return ret; } +inline bool QResourceRoot::nameMatches(int node, QStringView other) const +{ + if (!node) // root + return other.isEmpty(); + const int offset = findOffset(node); + + qint32 name_offset = qFromBigEndian(tree + offset); + qsizetype name_length = qFromBigEndian(names + name_offset); + name_offset += 2; + name_offset += 4; //jump past hash + + if (other.size() != name_length) + return false; + const QChar *strData = reinterpret_cast(names + name_offset); + for (qsizetype ch = 0; ch < name_length; ++ch) { + if (other.at(ch) != qFromBigEndian(strData + ch)) + return false; + } + return true; +} + int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const { QString path = _path; @@ -855,7 +877,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const --sub_node; for (; sub_node < child + child_count && hash(sub_node) == h; ++sub_node) { // here we go... - if (name(sub_node) == segment) { + if (nameMatches(sub_node, segment)) { found = true; int offset = findOffset(sub_node); #ifdef DEBUG_RESOURCE_MATCH diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_linux.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_linux.cpp index f706650c63..bec2f797c1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_linux.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_linux.cpp @@ -267,15 +267,14 @@ struct AutoFileDescriptor // udev encodes the labels with ID_LABEL_FS_ENC which is done with // blkid_encode_string(). Within this function some 1-byte utf-8 // characters not considered safe (e.g. '\' or ' ') are encoded as hex -static QString decodeFsEncString(QString &&str) +static QString decodeFsEncString(QString decoded) { using namespace QtMiscUtils; - qsizetype start = str.indexOf(u'\\'); + const qsizetype start = decoded.indexOf(u'\\'); if (start < 0) - return std::move(str); + return decoded; // decode in-place - QString decoded = std::move(str); auto ptr = reinterpret_cast(decoded.begin()); qsizetype in = start; qsizetype out = start; diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_p.h b/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_p.h index 0e3f81151e..7bced212cd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qstorageinfo_p.h @@ -81,7 +81,7 @@ public: subvolume = std::move(info.fsRoot); } - QStorageInfoPrivate(MountInfo &&info) + explicit QStorageInfoPrivate(MountInfo &&info) { setFromMountInfo(std::move(info)); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qurl.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qurl.cpp index 624645e94d..d9324b57be 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qurl.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qurl.cpp @@ -167,10 +167,9 @@ \li Spaces and "%20": unencoded space characters will be accepted and will be treated as equivalent to "%20". - \li Single "%" characters: Any occurrences of a percent character "%" not - followed by exactly two hexadecimal characters (e.g., "13% coverage.html") - will be replaced by "%25". Note that one lone "%" character will trigger - the correction mode for all percent characters. + \li Single "%" characters: if any percent character "%" is not followed by + two hexadecimal characters (e.g., "13% coverage.html"), the parser will + assume the input was not encoded and will replace all "%" characters with "%25". \li Reserved and unreserved characters: An encoded URL should only contain a few characters as literals; all other characters should diff --git a/local/recipes/qt/qtbase/source/src/corelib/io/qurlquery.cpp b/local/recipes/qt/qtbase/source/src/corelib/io/qurlquery.cpp index ede89584e7..1087c8bc84 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/io/qurlquery.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/io/qurlquery.cpp @@ -609,7 +609,9 @@ QChar QUrlQuery::queryPairDelimiter() const as the same, like HTML forms do. If you need spaces to be represented as plus signs, use actual plus signs. - \note The keys and values are expected to be in percent-encoded form. + \note The keys and values are expected to be in percent-encoded form. This + function will try to recover if improperly-encoded inputs are provided, but + that may produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa queryItems(), isEmpty() */ @@ -655,7 +657,9 @@ QList > QUrlQuery::queryItems(QUrl::ComponentFormatt Returns \c true if there is a query string pair whose key is equal to \a key from the URL. - \note The key expected to be in percent-encoded form. + \note The key expected to be in percent-encoded form. This function will + try to recover if an improperly-encoded input is provided, but that may + produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa addQueryItem(), queryItemValue() */ @@ -676,6 +680,9 @@ bool QUrlQuery::hasQueryItem(const QString &key) const plus signs, use actual plus signs. \note The key and value strings are expected to be in percent-encoded form. + This function will try to recover if improperly-encoded inputs are + provided, but that may produce data loss. See \l{QUrlQuery#Encoding} for + more information. \sa hasQueryItem(), queryItemValue() */ @@ -695,7 +702,9 @@ void QUrlQuery::addQueryItem(const QString &key, const QString &value) one found, in the order they were present in the query string or added using addQueryItem(). - \note The key is expected to be in percent-encoded form. + \note The key is expected to be in percent-encoded form. This function will + try to recover if an improperly-encoded input is provided, but that may + produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa addQueryItem(), allQueryItemValues(), {encoding}{Encoding} */ @@ -715,7 +724,9 @@ QString QUrlQuery::queryItemValue(const QString &key, QUrl::ComponentFormattingO the URL, using the options specified in \a encoding to encode the return value. If the key \a key is not found, this function returns an empty list. - \note The key is expected to be in percent-encoded form. + \note The key is expected to be in percent-encoded form. This function will + try to recover if an improperly-encoded input is provided, but that may + produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa queryItemValue(), addQueryItem() */ @@ -739,7 +750,9 @@ QStringList QUrlQuery::allQueryItemValues(const QString &key, QUrl::ComponentFor item in the order they were present in the query string or added with addQueryItem(). - \note The key is expected to be in percent-encoded form. + \note The key is expected to be in percent-encoded form. This function will + try to recover if an improperly-encoded input is provided, but that may + produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa removeAllQueryItems() */ @@ -757,7 +770,9 @@ void QUrlQuery::removeQueryItem(const QString &key) Removes all the query string pairs whose key is equal to \a key from the URL. - \note The key is expected to be in percent-encoded form. + \note The key is expected to be in percent-encoded form. This function will + try to recover if an improperly-encoded input is provided, but that may + produce data loss. See \l{QUrlQuery#Encoding} for more information. \sa removeQueryItem() */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/ipc/qsharedmemory_posix.cpp b/local/recipes/qt/qtbase/source/src/corelib/ipc/qsharedmemory_posix.cpp index fa215c3b53..2614759198 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/ipc/qsharedmemory_posix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/ipc/qsharedmemory_posix.cpp @@ -21,10 +21,6 @@ #include "private/qcore_unix_p.h" -#ifndef O_CLOEXEC -# define O_CLOEXEC 0 -#endif - QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; @@ -68,7 +64,7 @@ bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size) const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey()); int fd; - QT_EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600)); + QT_EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL, 0600)); if (fd == -1) { const int errorNumber = errno; const auto function = "QSharedMemory::attach (shm_open)"_L1; @@ -104,7 +100,7 @@ bool QSharedMemoryPosix::attach(QSharedMemoryPrivate *self, QSharedMemory::Acces const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR); const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600); - QT_EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode)); + QT_EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag, omode)); if (hand == -1) { const int errorNumber = errno; const auto function = "QSharedMemory::attach (shm_open)"_L1; diff --git a/local/recipes/qt/qtbase/source/src/corelib/ipc/qtipccommon.h b/local/recipes/qt/qtbase/source/src/corelib/ipc/qtipccommon.h index 375100f983..312392ed87 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/ipc/qtipccommon.h +++ b/local/recipes/qt/qtbase/source/src/corelib/ipc/qtipccommon.h @@ -59,7 +59,7 @@ public: QNativeIpcKey(QNativeIpcKey &&other) noexcept : d(std::exchange(other.d, nullptr)), key(std::move(other.key)), - typeAndFlags(std::move(other.typeAndFlags)) + typeAndFlags(other.typeAndFlags) { if (isSlowPath()) move_internal(std::move(other)); diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel.cpp index 3f843edeed..667f63291c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel.cpp @@ -49,6 +49,17 @@ QT_BEGIN_NAMESPACE \brief the source model of this proxy model. */ +QAbstractProxyModelPrivate::QAbstractProxyModelPrivate() + : QAbstractItemModelPrivate(), + sourceHadZeroRows(false), + sourceHadZeroColumns(false), + updateVerticalHeader(false), + updateHorizontalHeader(false) +{} + +QAbstractProxyModelPrivate::~QAbstractProxyModelPrivate() + = default; + //detects the deletion of the source model void QAbstractProxyModelPrivate::_q_sourceModelDestroyed() { diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel_p.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel_p.h index 68043fe890..9ecd14d3f4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qabstractproxymodel_p.h @@ -29,13 +29,9 @@ class Q_CORE_EXPORT QAbstractProxyModelPrivate : public QAbstractItemModelPrivat { Q_DECLARE_PUBLIC(QAbstractProxyModel) public: - QAbstractProxyModelPrivate() - : QAbstractItemModelPrivate(), - sourceHadZeroRows(false), - sourceHadZeroColumns(false), - updateVerticalHeader(false), - updateHorizontalHeader(false) - {} + QAbstractProxyModelPrivate(); + ~QAbstractProxyModelPrivate() override; + void setModelForwarder(QAbstractItemModel *sourceModel) { q_func()->setSourceModel(sourceModel); diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp index 6d7b8f89b7..e48a6f5452 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp @@ -3,11 +3,17 @@ // Qt-Security score:significant reason:default #include "qconcatenatetablesproxymodel.h" + #include + #include "qsize.h" #include "qmap.h" +#include #include "qdebug.h" +#include +#include + QT_BEGIN_NAMESPACE class QConcatenateTablesProxyModelPrivate : public QAbstractItemModelPrivate @@ -56,20 +62,37 @@ public: struct ModelInfo { using ConnArray = std::array; - ModelInfo(QAbstractItemModel *m, ConnArray &&con) - : model(m), connections(std::move(con)) {} + template + using if_compatible = std::enable_if_t< + sizeof...(Args) == std::tuple_size_v && + std::conjunction_v< + // only non-references (= rvalues), only non-const + std::is_same... + >, + bool>; + Q_DISABLE_COPY(ModelInfo) + ModelInfo(ModelInfo &&) = default; + ModelInfo &operator=(ModelInfo &&) = default; + template = true> + explicit ModelInfo(QAbstractItemModel *m, Args&&...args) + : model(m), connections{std::forward(args)...} {} QAbstractItemModel *model = nullptr; ConnArray connections; }; - QList m_models; + QVarLengthArray m_models; mutable QHash m_roleNames; - QList::const_iterator findSourceModel(const QAbstractItemModel *m) const + const ModelInfo *findSourceModel(const QAbstractItemModel *m) const { auto byModelPtr = [m](const auto &modInfo) { return modInfo.model == m; }; return std::find_if(m_models.cbegin(), m_models.cend(), byModelPtr); } + ModelInfo *findSourceModel(const QAbstractItemModel *m) + { + return const_cast(std::as_const(*this).findSourceModel(m)); + } + bool containsSourceModel(const QAbstractItemModel *m) const { return findSourceModel(m) != m_models.cend(); } @@ -366,7 +389,7 @@ bool QConcatenateTablesProxyModelPrivate::mapDropCoordinatesToSource(int row, in // Drop after the last item if (row == -1 || row == m_rowCount) { *sourceRow = -1; - *sourceModel = m_models.constLast().model; + *sourceModel = m_models.back().model; return true; } // Drop between toplevel items @@ -476,7 +499,7 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode if (newRows > 0) beginInsertRows(QModelIndex(), d->m_rowCount, d->m_rowCount + newRows - 1); d->m_rowCount += newRows; - d->m_models.emplace_back(sourceModel, std::array{ + d->m_models.emplace_back(sourceModel, QObjectPrivate::connect(sourceModel, &QAbstractItemModel::dataChanged, d, &QConcatenateTablesProxyModelPrivate::slotDataChanged), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsInserted, @@ -512,8 +535,8 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, d, &QConcatenateTablesProxyModelPrivate::slotModelAboutToBeReset), QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelReset, - d, &QConcatenateTablesProxyModelPrivate::slotModelReset), - }); + d, &QConcatenateTablesProxyModelPrivate::slotModelReset) + ); if (!d->m_roleNamesDirty) { // do update immediately, since append() is a simple update: const auto newRoleNames = sourceModel->roleNames(); @@ -536,7 +559,7 @@ void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceM Q_D(QConcatenateTablesProxyModel); auto it = d->findSourceModel(sourceModel); - Q_ASSERT(it != d->m_models.cend()); + Q_ASSERT(it != d->m_models.end()); for (auto &c : it->connections) disconnect(c); diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel.cpp index c0a5f6bf17..bb47146c7c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel.cpp @@ -9,6 +9,9 @@ QT_BEGIN_NAMESPACE +QIdentityProxyModelPrivate::QIdentityProxyModelPrivate() + = default; + QIdentityProxyModelPrivate::~QIdentityProxyModelPrivate() = default; @@ -290,14 +293,15 @@ void QIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel) // Call QObject::disconnect() unconditionally, if there is an existing source // model, it's disconnected, and if there isn't, then calling disconnect() on // a default-constructed Connection does nothing - for (const auto &c : d->m_sourceModelConnections) + for (auto &c : d->m_sourceModelConnections) QObject::disconnect(c); QAbstractProxyModel::setSourceModel(newSourceModel); if (sourceModel()) { auto *m = sourceModel(); - d->m_sourceModelConnections = { + using C = QMetaObject::Connection; + d->m_sourceModelConnections = std::array{ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted, d, &QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted), QObjectPrivate::connect(m, &QAbstractItemModel::rowsInserted, d, @@ -328,21 +332,16 @@ void QIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel) &QIdentityProxyModelPrivate::sourceModelReset), QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d, &QIdentityProxyModelPrivate::sourceHeaderDataChanged), - }; - - if (d->m_handleDataChanges) { - d->m_sourceModelConnections.emplace_back( + !d->m_handleDataChanges ? C{} : QObjectPrivate::connect(m, &QAbstractItemModel::dataChanged, d, - &QIdentityProxyModelPrivate::sourceDataChanged)); - } - if (d->m_handleLayoutChanges) { - d->m_sourceModelConnections.emplace_back( + &QIdentityProxyModelPrivate::sourceDataChanged), + !d->m_handleLayoutChanges ? C{} : QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d, - &QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged)); - d->m_sourceModelConnections.emplace_back( + &QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged), + !d->m_handleLayoutChanges ? C{} : QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d, - &QIdentityProxyModelPrivate::sourceLayoutChanged)); - } + &QIdentityProxyModelPrivate::sourceLayoutChanged), + }; } endResetModel(); diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel_p.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel_p.h index a3edef2ad4..18c15a043c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qidentityproxymodel_p.h @@ -20,6 +20,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate @@ -27,9 +29,7 @@ class Q_CORE_EXPORT QIdentityProxyModelPrivate : public QAbstractProxyModelPriva Q_DECLARE_PUBLIC(QIdentityProxyModel) public: - QIdentityProxyModelPrivate() - { - } + QIdentityProxyModelPrivate(); ~QIdentityProxyModelPrivate() override; QList layoutChangePersistentIndexes; @@ -67,7 +67,7 @@ public: private: bool m_handleLayoutChanges = true; bool m_handleDataChanges = true; - QVarLengthArray m_sourceModelConnections; + std::array m_sourceModelConnections; }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.cpp index 4f029106e4..5b564ca208 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.cpp @@ -63,10 +63,10 @@ struct PropertyChangedHandler // we can assign a connection to a moved-from handler to update the // handler stored in the QSlotObject/QCallableObject. - PropertyChangedHandler &operator=(const QMetaObject::Connection &connection) noexcept + PropertyChangedHandler &operator=(QMetaObject::Connection &&connection) { Q_ASSERT(std::holds_alternative(storage)); - std::get(storage)->connection = connection; + std::get(storage)->connection = std::move(connection); return *this; } @@ -207,7 +207,7 @@ bool QRangeModelImplBase::connectProperty(const QModelIndex &index, const QObjec // This assignment updates the stored handler's connection with the // QMetaObject::Connection handle, and should look harmless for // static analyzers. - handler = connection; + handler = std::move(connection); } return true; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.h index c16562c9b8..43011afaa0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel.h @@ -137,6 +137,10 @@ QModelIndex QRangeModelImplBase::createIndex(int row, int column, const void *pt { return m_rangeModel->createIndex(row, column, ptr); } +QModelIndexList QRangeModelImplBase::persistentIndexList() const +{ + return m_rangeModel->persistentIndexList(); +} void QRangeModelImplBase::changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to) { diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel_impl.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel_impl.h index 0682dae1ac..b3f2967d71 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodel_impl.h @@ -1057,6 +1057,7 @@ protected: {} inline QModelIndex createIndex(int row, int column, const void *ptr = nullptr) const; + inline QModelIndexList persistentIndexList() const; inline void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to); inline void dataChanged(const QModelIndex &from, const QModelIndex &to, const QList &roles); @@ -1392,10 +1393,9 @@ public: QModelRoleDataSpan roleDataSpan(roleDataArray); multiData(index, roleDataSpan); - for (auto &&roleData : std::move(roleDataSpan)) { - QVariant data = roleData.data(); - if (data.isValid()) - result[roleData.role()] = std::move(data); + for (QModelRoleData &roleData : roleDataSpan) { + if (roleData.data().isValid()) + result[roleData.role()] = std::move(roleData.data()); } } } @@ -1639,15 +1639,12 @@ public: template void updateTarget(LHS &org, RHS &©) noexcept { - if constexpr (std::is_pointer_v) { + if constexpr (std::is_pointer_v) return; - } else { - using std::swap; - if constexpr (std::is_assignable_v) - org = std::forward(copy); - else - qSwap(org, copy); - } + else if constexpr (std::is_assignable_v) + org = std::forward(copy); + else + qSwap(org, copy); } template void updateTarget(LHS *org, RHS &©) noexcept @@ -2762,8 +2759,25 @@ protected: } void resetParentInChildren(range_type *children) + { + const auto persistentIndexList = this->persistentIndexList(); + const auto [firstColumn, lastColumn] = [&persistentIndexList]{ + int first = std::numeric_limits::max(); + int last = -1; + for (const auto &pmi : persistentIndexList) { + first = (std::min)(pmi.column(), first); + last = (std::max)(pmi.column(), last); + } + return std::pair(first, last); + }(); + + resetParentInChildrenRecursive(children, firstColumn, lastColumn); + } + + void resetParentInChildrenRecursive(range_type *children, int pmiFromColumn, int pmiToColumn) { if constexpr (tree_traits::has_setParentRow && !rows_are_any_refs_or_pointers) { + const bool changePersistentIndexes = pmiToColumn >= pmiFromColumn; const auto begin = QRangeModelDetails::adl_begin(*children); const auto end = QRangeModelDetails::adl_end(*children); for (auto it = begin; it != end; ++it) { @@ -2772,22 +2786,29 @@ protected: auto &childrenRef = QRangeModelDetails::refTo(maybeChildren); QModelIndexList fromIndexes; QModelIndexList toIndexes; - fromIndexes.reserve(Base::size(childrenRef)); - toIndexes.reserve(Base::size(childrenRef)); + if (changePersistentIndexes) { + fromIndexes.reserve(Base::size(childrenRef) * (pmiToColumn - pmiFromColumn + 1)); + toIndexes.reserve(Base::size(childrenRef) * (pmiToColumn - pmiFromColumn + 1)); + } auto *parentRow = QRangeModelDetails::pointerTo(*it); int row = 0; for (auto &child : childrenRef) { const_row_ptr oldParent = this->protocol().parentRow(child); if (oldParent != parentRow) { - fromIndexes.append(this->createIndex(row, 0, oldParent)); - toIndexes.append(this->createIndex(row, 0, parentRow)); + if (changePersistentIndexes) { + for (int column = pmiFromColumn; column <= pmiToColumn; ++column) { + fromIndexes.append(this->createIndex(row, column, oldParent)); + toIndexes.append(this->createIndex(row, column, parentRow)); + } + } this->protocol().setParentRow(child, parentRow); } ++row; } - this->changePersistentIndexList(fromIndexes, toIndexes); - resetParentInChildren(&childrenRef); + if (changePersistentIndexes) + this->changePersistentIndexList(fromIndexes, toIndexes); + resetParentInChildrenRecursive(&childrenRef, pmiFromColumn, pmiToColumn); } } } diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.h index 5d7cc553f4..8672144f62 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.h @@ -147,9 +147,15 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter public: struct DataReference { +#ifdef Q_QDOC + using value_type = int; + using const_value_type = const int; + using pointer = void *; +#else using value_type = data_type; using const_value_type = const_data_type; using pointer = QRangeModelDetails::data_pointer_t; +#endif explicit DataReference(const QModelIndex &index) noexcept : m_index(index) @@ -646,6 +652,9 @@ public: using const_iterator = typename Base::const_iterator; using size_type = typename Base::size_type; using difference_type = typename Base::difference_type; +#ifdef Q_QDOC + using row_type = int; +#endif using const_row_type = typename Base::const_row_type; using Base::Base; @@ -1592,7 +1601,7 @@ private: template void assignImpl(std::size_t newSize, Assigner &&assigner) { - const auto sz = q26::saturate_cast(newSize); + const auto sz = q26::saturating_cast(newSize); Q_ASSERT_X(q20::cmp_equal(sz, newSize), "QRangeModelAdapter::assign", "New range is too large"); const int newLastRow = sz - 1; diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.qdoc b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.qdoc index 3933480597..2767bec42c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter.qdoc @@ -72,8 +72,9 @@ range that the model operates on. The adapter API is based on the typical API for C++ containers and ranges, including iterators. To access individual rows and items, use at(), the corresponding subscript - \c{operator[]}, or data(). Which overloads of those functions are available - depends on the range for which the adapter was constructed. + \l{QRangeModelAdapter::operator[]()}{operator[]}, or data(). + Which overloads of those functions are available depends on the range for + which the adapter was constructed. \section2 Reading item data as a QVariant @@ -109,11 +110,11 @@ regular C++ containers. As with data(), at() overloads exist to access an item at a row for lists, at a row/column pair for table, and a path/column pair for trees. However, at() always returns the whole item at the - specified position; it's not possible to read an individual role values for + specified position; it is not possible to read individual role values of an item. As expected from a C++ container API, the const overloads of at() (and the - corresponding subscript \c{operator[]}) provide immutable access to the + corresponding subscript \l{operator[]()}) provide immutable access to the value, while the mutable overloads return a reference object that a new value can be assigned to. Note that a QRangeModelAdapter operating on a const range behaves in that respect like a const QRangeModelAdapter. The @@ -125,11 +126,12 @@ \snippet qrangemodeladapter/main.cpp read-only The returned reference objects are wrappers that convert implicitly to the - underlying type, have a \c{get()} function to explicitly access the - underlying value, and an \c{operator->()} that provides direct access to - const member functions. However, to prevent accidental data changes that - would bypass the QAbstractItemModel notification protocol, those reference - objects prevent direct modifications of the items. + underlying type, have a \l{QRangeModelAdapter::DataReference::}{get()} + function to explicitly access the underlying value, and an + \l{QRangeModelAdapter::DataReference::}{operator->()} that provides direct + access to const member functions. However, to prevent accidental data + changes that would bypass the QAbstractItemModel notification protocol, + those reference objects prevent direct modifications of the items. \note Accessing the reference object always makes a call to the model to get a copy of the value. This can be expensive; for performance critical access @@ -167,7 +169,7 @@ this item, and for all roles. If the range is represented as a table, then you can access an individual - item by row and columns, using the \l{at(int, int)}{at(row, column)} + item by row and column, using the \l{at(int, int)}{at(row, column)} overload. For trees, that overload gives access to top-level items, while the \l{at(QSpan, int)}{at(path, column)} overload provides access to items nested within the tree. @@ -178,14 +180,14 @@ \snippet qrangemodeladapter/main.cpp table-item-access If the range doesn't store all columns using the same data type, then - \c{at(row,column)} returns a (a reference wrapper with a) QVariant holding + \c{at(row,column)} returns a (reference wrapper with a) QVariant holding the item. \snippet qrangemodeladapter/main.cpp table-mixed-type-access \section2 Accessing rows in tables and trees - For tables and trees, the overloads of at() and subscript \c{operator[]} + For tables and trees, the overloads of at() and subscript \l{operator[]()} without the column parameter provide access to the entire row. The value returned by the const overloads will be a reference type that gives access to the row data. If that row holds pointers, then that reference type will @@ -194,7 +196,7 @@ \section3 Table row access The \l{at(int)} overload is still available, but it returns the entire table - wor. This makes it possible to work with all the values in the row at once. + row. This makes it possible to work with all the values in the row at once. \snippet qrangemodeladapter/main.cpp table-row-const-access @@ -259,9 +261,9 @@ \snippet qrangemodeladapter/main.cpp ranged-for-const-table Both the const and the mutable iterator will dereference to a wrapper type - for the row. This make sure that we can consistently iterate over each - column, even if the underlying row type is not a range (e.g. it might be a - tuple or gadget). + for the row. This makes sure that we can consistently iterate over each + item in the row, even if the underlying row type is not a range (e.g. it + might be a tuple or gadget). \snippet qrangemodeladapter/main.cpp ranged-for-const-table-items @@ -373,19 +375,19 @@ */ /*! - \fn template template ::if_list> QModelIndex QRangeModelAdapter::index(int row) const + \fn template template ::if_list> QModelIndex QRangeModelAdapter::index(int listRow) const \overload - Returns the QModelIndex for \a row. + Returns the QModelIndex for \a listRow. \constraints \c Range is a one-dimensional list. */ /*! - \fn template template ::unless_list> QModelIndex QRangeModelAdapter::index(int row, int column) const + \fn template template ::unless_list> QModelIndex QRangeModelAdapter::index(int tableRow, int column) const \overload - Returns the QModelIndex for the item at \a row, \a column. + Returns the QModelIndex for the item at \a tableRow, \a column. \constraints \c Range is a table or tree. */ @@ -434,11 +436,11 @@ */ /*! - \fn template template ::if_list> QVariant QRangeModelAdapter::data(int row) const - \fn template template ::if_list> QVariant QRangeModelAdapter::data(int row, int role) const + \fn template template ::if_list> QVariant QRangeModelAdapter::data(int listRow) const + \fn template template ::if_list> QVariant QRangeModelAdapter::data(int listRow, int role) const \return a QVariant holding the data stored under the given \a role for the - item at \a row, or an invalid QVariant if there is no item. If \a role is + item at \a listRow, or an invalid QVariant if there is no item. If \a role is not specified, then returns a QVariant holding the complete item. \constraints \c Range is a list. @@ -447,9 +449,9 @@ */ /*! - \fn template template ::if_list, QRangeModelAdapter::if_writable> bool QRangeModelAdapter::setData(int row, const QVariant &value, int role) + \fn template template ::if_list, QRangeModelAdapter::if_writable> bool QRangeModelAdapter::setData(int listRow, const QVariant &value, int role) - Sets the \a role data for the item at \a row to \a value. + Sets the \a role data for the item at \a listRow to \a value. Returns \c{true} if successful; otherwise returns \c{false}. @@ -459,11 +461,11 @@ */ /*! - \fn template template ::unless_list> QVariant QRangeModelAdapter::data(int row, int column) const - \fn template template ::unless_list> QVariant QRangeModelAdapter::data(int row, int column, int role) const + \fn template template ::unless_list> QVariant QRangeModelAdapter::data(int tableRow, int column) const + \fn template template ::unless_list> QVariant QRangeModelAdapter::data(int tableRow, int column, int role) const \return a QVariant holding the data stored under the given \a role for the - item referred to by a \a row and \a column, or an invalid QVariant if there + item referred to by a \a tableRow and \a column, or an invalid QVariant if there is no data stored for that position or role. If \a role is not specified, then returns a QVariant holding the complete item. @@ -473,9 +475,9 @@ */ /*! - \fn template template ::unless_list, QRangeModelAdapter::if_writable> bool QRangeModelAdapter::setData(int row, int column, const QVariant &value, int role) + \fn template template ::unless_list, QRangeModelAdapter::if_writable> bool QRangeModelAdapter::setData(int tableRow, int column, const QVariant &value, int role) - Sets the \a role data for the item referred to by \a row and \a column to + Sets the \a role data for the item referred to by \a tableRow and \a column to \a value. Returns \c{true} if successful; otherwise returns \c{false}. @@ -513,20 +515,20 @@ */ /*! - \fn template template ::if_list> auto QRangeModelAdapter::at(int row) const - \fn template template ::if_list> auto QRangeModelAdapter::operator[](int row) const + \fn template template ::if_list> auto QRangeModelAdapter::at(int listRow) const + \fn template template ::if_list> auto QRangeModelAdapter::operator[](int listRow) const - \return the value at \a row as the type stored in \c Range. + \return the value at \a listRow as the type stored in \c Range. \constraints \c Range is a list. */ /*! - \fn template template ::if_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int row) - \fn template template ::if_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int row) + \fn template template ::if_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int listRow) + \fn template template ::if_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int listRow) - \return the value at \a row wrapped into a mutable reference to the type - stored in \c Range. + \return a \l{DataReference}{mutable reference} to the value stored in + \c Range. //! [data-ref] \note Modifications to the range will invalidate that reference. To modify @@ -539,28 +541,30 @@ */ /*! - \fn template template ::unless_list> decltype(auto) QRangeModelAdapter::at(int row) const - \fn template template ::unless_list> decltype(auto) QRangeModelAdapter::operator[](int row) const + \fn template template ::unless_list> decltype(auto) QRangeModelAdapter::at(int tableRow) const + \fn template template ::unless_list> decltype(auto) QRangeModelAdapter::operator[](int tableRow) const - \return a constant reference to the row at \a row, as stored in \c Range. + \return a constant reference to the row at \a tableRow, as stored in \c Range. \constraints \c Range is a table or tree. */ /*! - \fn template template ::if_table, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int row) - \fn template template ::if_table, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int row) + \fn template template ::if_table, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int tableRow) + \fn template template ::if_table, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int tableRow) - \return a mutable reference to the row at \a row, as stored in \c Range. + \return a \l{QRangeModelAdapter::RowReference}{reference wrapper} to the row + at \a tableRow, as stored in \c Range. \constraints \c Range is a mutable table, but not a tree. */ /*! - \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int row) - \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int row) + \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int treeRow) + \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int treeRow) - \return a mutable wrapper holding a reference to the tree row specified by \a row. + \return a \l{QRangeModelAdapter::RowReference}{reference wrapper} to the row + at \a treeRow, as stored in \c Range. //! [treerow-ref] To modify the tree row, assign a new value to it. Assigning a new tree row @@ -576,12 +580,12 @@ */ /*! - \fn template template ::unless_list> auto QRangeModelAdapter::at(int row, int column) const + \fn template template ::unless_list> auto QRangeModelAdapter::at(int tableRow, int column) const \omit - \fn template template ::unless_list> auto QRangeModelAdapter::operator[](int row, int column) const + \fn template template ::unless_list> auto QRangeModelAdapter::operator[](int tableRow, int column) const \endomit - \return a copy of the value stored as the item specified by \a row and + \return a copy of the value stored as the item specified by \a tableRow and \a column. If the item is a multi-role item, then this returns a copy of the entire item. If the rows in the \c Range store different types at different columns, then the return type will be a QVariant. @@ -590,14 +594,14 @@ */ /*! - \fn template template ::unless_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int row, int column) + \fn template template ::unless_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(int tableRow, int column) \omit - \fn template template ::unless_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int row, int column) + \fn template template ::unless_list, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](int tableRow, int column) \endomit - \return a mutable reference to the value stored as the item specified by - \a row and \a column. If the item is a multi-role item, then this will be - a reference to the entire item. + \return a \l{DataReference}{mutable reference} to the value stored as the + item specified by \a tableRow and \a column. If the item is a multi-role item, + then this will be a reference to the entire item. \include qrangemodeladapter.qdoc data-ref @@ -618,7 +622,8 @@ \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::at(QSpan path) \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](QSpan path) - \return a mutable wrapper holding a reference to the tree row specified by \a path. + \return a \l{RowReference}{mutable wrapper} holding a reference to the tree + row specified by \a path. \include qrangemodeladapter.qdoc treerow-ref @@ -645,10 +650,11 @@ \fn template template ::if_tree, QRangeModelAdapter::if_writable> auto QRangeModelAdapter::operator[](QSpan path, int column) \endomit - \return a mutable reference to the value stored as the item specified by - \a path and \a column. If the item is a multi-role item, then this will be - a reference to the entire item. If the rows in the \c Range store different - types at different columns, then the return type will be a QVariant. + \return a \l{DataReference}{mutable reference} to the value stored as the + item specified by \a path and \a column. If the item is a multi-role item, + then this will be a reference to the entire item. If the rows in the \c + Range store different types at different columns, then the return type will + be a QVariant. \include qrangemodeladapter.qdoc data-ref @@ -719,7 +725,7 @@ \a before, and returns whether the insertion was successful. \include qrangemodeladapter.qdoc insert-row-appends - \constraints \c Range supports insertion of elemnets, and if + \constraints \c Range supports insertion of elements, and if rows can be constructed from the elements in \a data. \sa insertRow(), removeRows(), insertColumns() @@ -959,3 +965,351 @@ \fn template template ::if_canMoveItems, QRangeModelAdapter::if_tree> bool QRangeModelAdapter::moveColumns(QSpan source, int count, int to) \internal Not possible to create a tree from a row type that can rotate/splice? */ + +/*! + \class QRangeModelAdapter::DataReference + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief DataReference is a reference wrapper around an item in a QRangeModel. + + Accessing an item in the model using the non-const overloads of at(), + subscript \l{QRangeModelAdapter::operator[]()}{operator[]}, or + dereferencing a non-const \l{QRangeModelAdapter::RowIterator}{iterator}, + returns a DataReference wrapper around the item in the model. + + Assigning to that reference wrapper changes the data in the model using + QAbstractItemModel API. + + \code + adapter[0] = newValue; + \endcode + + A const version of the value itself can be accessed using get() or + operator->(). + + \code + QRangeModelAdapter adapter(QList{ ~~~ }); + auto value = adapter[0]->value(); + // adapter[0]->setValue(); // not allowed - would not emit dataChanged() + \endcode + + In contrast to \c{std::reference_wrapper}, assigning one DataReference to + another does not rebind the reference, but sets the value using copy- + semantics. + + \code + adapter[0] = adapter[1]; // items at row 0 and row 1 now have the same value + \endcode + + \sa RowReference, ConstRowReference +*/ + +/*! + \typedef QRangeModelAdapter::DataReference::value_type + + An alias for the type of the items stored in the underlying range. + If different columns in the model hold different types, then this is an + alias to QVariant. +*/ + +/*! + \typedef QRangeModelAdapter::DataReference::const_value_type + + An alias for the const type of the items stored in the underlying range. + If different columns in the model hold different types, then this is an + alias to \c{const QVariant}. +*/ + +/*! + \typedef QRangeModelAdapter::DataReference::pointer + + An alias for the pointer type returned by operator->(). +*/ + +/*! + \fn template QRangeModelAdapter::DataReference::DataReference(const QModelIndex &index) noexcept + + Constructs a DataReference wrapper for the item at \a index. +*/ + +/*! + \fn template QRangeModelAdapter::DataReference::DataReference(const DataReference &other) + + Constructs a copy of \a other. +*/ + +/*! + \fn template QRangeModelAdapter::DataReference::DataReference(DataReference &&other) + + Constructs a DataReference by moving from \a other. +*/ + +/*! + \fn template QDataReference &QRangeModelAdapter::DataReference::operator=(const DataReference &other) + + Assigns the item value referred to by \a other to the value referenced by this wrapper. +*/ + +/*! + \fn template DataReference &QRangeModelAdapter::DataReference::operator=(DataReference &&other) + + Moves the value reference by \a other into the value referenced by this wrapper. +*/ + +/*! + \fn template DataReference &QRangeModelAdapter::DataReference::operator=(const value_type &value) + + Assigns \a value to the underlying model item. +*/ + +/*! + \fn template DataReference &QRangeModelAdapter::DataReference::operator=(value_type &&value) + + Move-assigns \a value to the underlying model item. +*/ + +/*! + \fn template const_value_type QRangeModelAdapter::DataReference::get() const + \fn template QRangeModelAdapter::DataReference::operator const_value_type() const + \return the item value referred to by this DataReference as a const value. +*/ + +/*! + \fn template pointer QRangeModelAdapter::DataReference::operator->() const + \return a pointer to the value referred to by this DataReference. +*/ + +/*! + \fn template bool QRangeModelAdapter::DataReference::isValid() const + \return true if this DataReference refers to a valid model index. +*/ + +/*! + \class QRangeModelAdapter::RowReferenceBase + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief RowReferenceBase provides common API for RowReference and ConstRowReference. + + For models that are tables or trees, accessing a row of an adapter using + \l{QRangeModelAdapter::}{at()}, subscript \l{QRangeModelAdapter::operator[]()} + {operator[]}, or dereferencing a RowIterator, returns a RowReference or + ConstRowReference to the specified row. + + \sa DataReference +*/ + +/*! + \fn template template template ::if_tree> bool QRangeModelAdapter::RowReferenceBase::hasChildren() const + + \return true if the referenced row has one or more child rows, otherwise false. + + \constraints \c Range is a tree. +*/ + +/*! + \fn template template template ::if_tree> auto QRangeModelAdapter::RowReferenceBase::children() const + + \return a QRangeModelAdapter operating on the same range and model as this adapter, and with + this row as the root index. + + \constraints \c Range is a tree. +*/ + +/*! + \fn template template ConstColumnIterator QRangeModelAdapter::RowReferenceBase::cbegin() const + + \return a ConstColumnIterator pointing to the first column of this row. +*/ + +/*! + \fn template template ConstColumnIterator QRangeModelAdapter::RowReferenceBase::begin() const + + \return a ConstColumnIterator pointing to the first column of this row. +*/ + +/*! + \fn template template ConstColumnIterator QRangeModelAdapter::RowReferenceBase::cend() const + + \return a ConstColumnIterator pointing just after the last column of this row. +*/ + +/*! + \fn template template ConstColumnIterator QRangeModelAdapter::RowReferenceBase::end() const + + \return a ConstColumnIterator pointing just after the last column of this row. +*/ + +/*! + \fn template template size_type QRangeModelAdapter::RowReferenceBase::size() const + + \return the number of columns in the model. + + This returns the same value for all rows in the model. +*/ + +/*! + \fn template template auto QRangeModelAdapter::RowReferenceBase::at(int column) const + \fn template template auto QRangeModelAdapter::RowReferenceBase::operator[](int column) const + + \return a reference wrapper to the item at \a column of this row. + + Depending on the data structure the adapter operates on, the returned value + is a const reference wrapper, a pointer to a const object, or a QVariant. +*/ + +/*! + \class QRangeModelAdapter::RowReference + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief RowReference is a reference wrapper around a row in a QRangeModel. + + For ranges that are tables or trees, accessing a row of a QRangeModelAdapter + using the non-const overloads of \l{QRangeModelAdapter::}{at()} or subscript + \l{QRangeModelAdapter::operator[]()}{operator[]}, or by dereferencing a + RowIterator, returns a RowReference for the specified row. + + \sa ConstRowReference, DataReference +*/ + +/*! + \typedef QRangeModelAdapter::RowReference::row_type + + An alias for the type of the rows in the underlying range. +*/ + +/*! + \fn template RowReference &QRangeModelAdapter::RowReference::operator=(const RowReference &other) + \fn template RowReference &QRangeModelAdapter::RowReference::operator=(const ConstRowReference &other) + + Assigns the row referenced by \a other to the row referenced by this, emitting + dataChanged for all items in the row. + +//! [rowref-assign] + If the model is a tree, and the referenced row has children, then those children + are removed from the model. If the row referenced by \a other has children, + then those children are inserted into the model. +//! [rowref-assign] +*/ + +/*! + \fn template RowReference &QRangeModelAdapter::RowReference::operator=(const row_type &other) + \fn template RowReference &QRangeModelAdapter::RowReference::operator=(row_type &&other) + + Assigns the row \a other to the row referenced by this, emitting dataChanged + for all items in the row. + + \include qrangemodeladapter.qdoc rowref-assign +*/ + +/*! + \fn template QRangeModelAdapter::RowReference::operator ConstRowReference() const + + \return a ConstRowReference referencing the same row as this. +*/ + +/*! + \fn template template ::if_tree> auto QRangeModelAdapter::RowReference::children() + + \return a QRangeModelAdapter operating on the same range and model as this adapter, and with + this row as the root index. + + \constraints \c Range is a tree. +*/ + +/*! + \fn template ColumnIterator QRangeModelAdapter::RowReference::begin() + + \return a ColumnIterator pointing to the first column of this row. +*/ + +/*! + \fn template ColumnIterator QRangeModelAdapter::RowReference::end() + + \return a ColumnIterator pointing just after the last column of this row. +*/ + +/*! + \fn template auto QRangeModelAdapter::RowReference::at(int column) + \fn template auto QRangeModelAdapter::RowReference::operator[](int column) + + \return a reference wrapper to the item at \a column of this row. +*/ + + +/*! + \class QRangeModelAdapter::ConstRowReference + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief ConstRowReference is a reference wrapper around a const row in a QRangeModel. + + For ranges that are tables or trees, accessing a row of a QRangeModelAdapter + using the const overloads of \l{QRangeModelAdapter::}{at()} or subscript + \l{QRangeModelAdapter::operator[]()}{operator[]}, or by dereferencing a + ConstRowIterator, returns a ConstRowReference for the specified row. + + \sa RowReference, DataReference +*/ + +/*! + \class QRangeModelAdapter::RowIterator + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief Provides an STL-style non-const iterator over the rows of a model. + + The iterator models \c{std::random_access_iterator}. If the model is a list, + then dereferencing the iterator returns a DataReference wrapper for the + pointed-to item in the model. + + For tables and trees, dereferencing the iterator returns a RowReference for + the pointed-to row. +*/ + +/*! + \class QRangeModelAdapter::ConstRowIterator + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief Provides an STL-style const iterator over the rows of a model. + + The iterator models \c{std::random_access_iterator}. If the model is a list, + then dereferencing the iterator returns the pointed-to item in the model. + + For tables and trees, dereferencing the iterator returns a ConstRowReference + for the pointed-to row. +*/ + +/*! + \class QRangeModelAdapter::ColumnIterator + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief Provides an STL-style non-const iterator over the columns in a model row. + + The iterator models \c{std::random_access_iterator}. Dereferencing the iterator + returns a DataReference wrapper for the value at the pointed-to item in + the model. +*/ + +/*! + \class QRangeModelAdapter::ConstColumnIterator + \inmodule QtCore + \since 6.11 + \preliminary + \ingroup model-view + \brief Provides an STL-style non-const iterator over the columns in a model row. + + The iterator models \c{std::random_access_iterator}. Dereferencing the iterator + returns the const value at the pointed-to item in the model. +*/ diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter_impl.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter_impl.h index a321360950..c5ffe2ede7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qrangemodeladapter_impl.h @@ -361,7 +361,7 @@ struct ParentIndex template <> struct ParentIndex { - const QModelIndex m_rootIndex; + QModelIndex m_rootIndex; QModelIndex root() const { return m_rootIndex; } }; diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 5143618962..e06edb3927 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -527,8 +527,10 @@ IndexMap::const_iterator QSortFilterProxyModelPrivate::create_mapping_recursive( return end; } Mapping *gm = it.value(); - if (gm->proxy_rows.at(source_parent.row()) == -1 || - gm->proxy_columns.at(source_parent.column()) == -1) { + if (source_parent.row() >= gm->proxy_rows.size() + || gm->proxy_rows.at(source_parent.row()) == -1 + || source_parent.column() >= gm->proxy_columns.size() + || gm->proxy_columns.at(source_parent.column()) == -1) { // Can't do, parent is filtered return end; } @@ -2046,7 +2048,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) beginResetModel(); if (d->model) { - for (const QMetaObject::Connection &connection : std::as_const(d->sourceConnections)) + for (QMetaObject::Connection &connection : d->sourceConnections) disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel.cpp b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel.cpp index 9c80d5c6ed..5fe58faa56 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel.cpp @@ -11,6 +11,12 @@ QT_BEGIN_NAMESPACE +QTransposeProxyModelPrivate::QTransposeProxyModelPrivate() + = default; + +QTransposeProxyModelPrivate::~QTransposeProxyModelPrivate() + = default; + QModelIndex QTransposeProxyModelPrivate::uncheckedMapToSource(const QModelIndex &proxyIndex) const { if (!model || !proxyIndex.isValid()) @@ -173,14 +179,13 @@ void QTransposeProxyModel::setSourceModel(QAbstractItemModel* newSourceModel) return; beginResetModel(); if (d->model) { - for (const QMetaObject::Connection& discIter : std::as_const(d->sourceConnections)) + for (QMetaObject::Connection &discIter : d->sourceConnections) disconnect(discIter); } - d->sourceConnections.clear(); QAbstractProxyModel::setSourceModel(newSourceModel); if (d->model) { using namespace std::placeholders; - d->sourceConnections = QList{ + d->sourceConnections = std::array{ connect(d->model, &QAbstractItemModel::modelAboutToBeReset, this, &QTransposeProxyModel::beginResetModel), connect(d->model, &QAbstractItemModel::modelReset, this, &QTransposeProxyModel::endResetModel), connect(d->model, &QAbstractItemModel::dataChanged, this, std::bind(&QTransposeProxyModelPrivate::onDataChanged, d, _1, _2, _3)), diff --git a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel_p.h b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel_p.h index abb7346d83..03a83a884a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/itemmodels/qtransposeproxymodel_p.h @@ -17,8 +17,11 @@ // #include "qtransposeproxymodel.h" + #include +#include + QT_BEGIN_NAMESPACE class QTransposeProxyModelPrivate : public QAbstractProxyModelPrivate @@ -26,10 +29,14 @@ class QTransposeProxyModelPrivate : public QAbstractProxyModelPrivate Q_DECLARE_PUBLIC(QTransposeProxyModel) Q_DISABLE_COPY(QTransposeProxyModelPrivate) private: - QTransposeProxyModelPrivate() = default; - QList sourceConnections; + QTransposeProxyModelPrivate(); + ~QTransposeProxyModelPrivate() override; + QList layoutChangePersistentIndexes; QModelIndexList layoutChangeProxyIndexes; + std::array sourceConnections; + + QModelIndex uncheckedMapToSource(const QModelIndex &proxyIndex) const; QModelIndex uncheckedMapFromSource(const QModelIndex &sourceIndex) const; void onLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint); diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.cpp index 935708cf8b..9b4afe6bfe 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qabstracteventdispatcher.h" #include "qabstracteventdispatcher_p.h" @@ -60,7 +61,7 @@ template static T fromDuration(std::chrono::nanoseconds interval) { using namespace std::chrono; qint64 value = ceil(interval).count(); - return q26::saturate_cast(value); + return q26::saturating_cast(value); } #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) @@ -91,7 +92,7 @@ QAbstractEventDispatcherPrivate::QAbstractEventDispatcherPrivate() QAbstractEventDispatcherPrivate::~QAbstractEventDispatcherPrivate() = default; -int QAbstractEventDispatcherPrivate::allocateTimerId() +Qt::TimerId QAbstractEventDispatcherPrivate::allocateTimerId() { // This function may be called after timerIdFreeList() has been destructed // for example in case when application exits without waiting for @@ -99,16 +100,16 @@ int QAbstractEventDispatcherPrivate::allocateTimerId() // to a slot which triggers a sequence that registers new timer. // See https://bugreports.qt-project.org/browse/QTBUG-38957. if (QtTimerIdFreeList *fl = timerIdFreeList()) - return fl->next(); - return 0; // Note! returning 0 generates a warning + return Qt::TimerId{fl->next()}; + return Qt::TimerId{0}; // Note! returning 0 generates a warning } -void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) +void QAbstractEventDispatcherPrivate::releaseTimerId(Qt::TimerId timerId) { // this function may be called by a global destructor after // timerIdFreeList() has been destructed if (QtTimerIdFreeList *fl = timerIdFreeList()) - fl->release(timerId); + fl->release(qToUnderlying(timerId)); } /*! @@ -276,7 +277,7 @@ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timer Qt::TimerId QAbstractEventDispatcher::registerTimer(Duration interval, Qt::TimerType timerType, QObject *object) { - auto id = Qt::TimerId(QAbstractEventDispatcherPrivate::allocateTimerId()); + auto id = QAbstractEventDispatcherPrivate::allocateTimerId(); #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) if (QAbstractEventDispatcherV2 *self = v2(this)) self->registerTimer(id, interval, timerType, object); @@ -425,11 +426,6 @@ void QAbstractEventDispatcher::closingDown() \sa registeredTimers(), QAbstractEventDispatcher::TimerInfoV2, timersForObject() */ -/*! \fn QAbstractEventDispatcher::TimerInfo::TimerInfo(int timerId, int interval, Qt::TimerType timerType) - - Constructs a TimerInfo struct with the given \a timerId, \a interval, and - \a timerType. -*/ /*! \variable QAbstractEventDispatcher::TimerInfo::timerId diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.h index 410ed68c8d..9b838a12c3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:header-decls-only #ifndef QABSTRACTEVENTDISPATCHER_H #define QABSTRACTEVENTDISPATCHER_H @@ -25,9 +26,13 @@ public: int timerId; int interval; Qt::TimerType timerType; - +#ifndef Q_QDOC +#ifndef __cpp_aggregate_paren_init + TimerInfo() = default; inline TimerInfo(int id, int i, Qt::TimerType t) : timerId(id), interval(i), timerType(t) { } +#endif +#endif }; struct TimerInfoV2 { diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher_p.h index 2576027d52..69a33983bf 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstracteventdispatcher_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:trivial-impl-only #ifndef QABSTRACTEVENTDISPATCHER_P_H #define QABSTRACTEVENTDISPATCHER_P_H @@ -35,10 +36,10 @@ public: bool isV2 = false; - static int allocateTimerId(); - static void releaseTimerId(int id); - static void releaseTimerId(Qt::TimerId id) - { releaseTimerId(qToUnderlying(id)); } + static Qt::TimerId allocateTimerId(); + static void releaseTimerId(int id) + { releaseTimerId(Qt::TimerId{id}); } + static void releaseTimerId(Qt::TimerId id); static QAbstractEventDispatcherPrivate *get(QAbstractEventDispatcher *o) { return o->d_func(); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.cpp index fa1cf533be..deccb5c56c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qabstractnativeeventfilter.h" #include "qabstracteventdispatcher.h" @@ -22,9 +23,7 @@ QT_BEGIN_NAMESPACE object. */ QAbstractNativeEventFilter::QAbstractNativeEventFilter() -{ - Q_UNUSED(d); -} + = default; /*! Destroys the native event filter. @@ -33,6 +32,10 @@ QAbstractNativeEventFilter::QAbstractNativeEventFilter() */ QAbstractNativeEventFilter::~QAbstractNativeEventFilter() { +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + if (d) // check no-one took `d` into use on this object + qFatal("QAbstractNativeEventFilter::d is not to be used"); +#endif QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); if (eventDispatcher) eventDispatcher->removeNativeEventFilter(this); diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.h index 3660a31dba..87ea2f186d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qabstractnativeeventfilter.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:header-decls-only #ifndef QABSTRACTNATIVEEVENTFILTER_H #define QABSTRACTNATIVEEVENTFILTER_H @@ -8,7 +9,9 @@ QT_BEGIN_NAMESPACE +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) class QAbstractNativeEventFilterPrivate; +#endif class Q_CORE_EXPORT QAbstractNativeEventFilter { @@ -20,7 +23,10 @@ public: private: Q_DISABLE_COPY(QAbstractNativeEventFilter) - QAbstractNativeEventFilterPrivate *d; +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + Q_DECL_UNUSED_MEMBER + QAbstractNativeEventFilterPrivate *d = nullptr; +#endif }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qapplicationstatic.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qapplicationstatic.h index 345a880748..b9e47ef354 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qapplicationstatic.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qapplicationstatic.h @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QAPPLICATIONSTATIC_H #define QAPPLICATIONSTATIC_H @@ -67,8 +68,10 @@ template struct ApplicationHolder { // we only synchronize using the mutex here, not the guard QMutexLocker locker(&mutex); - realPointer()->~PlainType(); - guard.storeRelaxed(QtGlobalStatic::Uninitialized); + if (guard.loadRelaxed() == QtGlobalStatic::Initialized) { + realPointer()->~PlainType(); + guard.storeRelaxed(QtGlobalStatic::Uninitialized); + } } }; } // namespace QtGlobalStatic diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.cpp index bca9d43901..c66192f4f4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.h index 551bbed6b8..d7a8d03c98 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qassociativeiterable.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QASSOCIATIVEITERABLE_H #define QASSOCIATIVEITERABLE_H @@ -132,6 +133,10 @@ public: QVariant value(const QVariant &key) const; void setValue(const QVariant &key, const QVariant &mapped); + + // Random access iteration is broken on QAssociativeIterator. + // That's why this class is deprecated after all. + constexpr bool canRandomAccessIterate() const { return false; } }; template<> diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.cpp index 0c33425638..9fb06343a5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qbasictimer.h" #include "qabstracteventdispatcher.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.h index 39f098e320..1f3f6af235 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbasictimer.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QBASICTIMER_H #define QBASICTIMER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbindingstorage.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbindingstorage.h index 27fba0e4b9..7d9a757ea8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qbindingstorage.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qbindingstorage.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QBINDINGSTORAGE_H #define QBINDINGSTORAGE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier.cpp index 21a22a7439..2f1b5bd4ce 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qcfsocketnotifier_p.h" #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier_p.h index 9bffe132dd..c15ed03903 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcfsocketnotifier_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QCFSOCKETNOTIFIER_P_H #define QCFSOCKETNOTIFIER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.cpp index 76c05c07e5..d42fe8c576 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qchronotimer.h" #include "qtimer_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.h index 79f66f89c7..147cdd7a64 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qchronotimer.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QCHRONOTIMER_H #define QCHRONOTIMER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_mac_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_mac_p.h index 2c4b4c02c5..e1d3f0aac0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_mac_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_mac_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QCORE_MAC_P_H #define QCORE_MAC_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix.cpp index 6861251bc2..322ff98c25 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h index e94ffab8e7..83ba69d5fb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCORE_UNIX_P_H #define QCORE_UNIX_P_H @@ -65,7 +66,7 @@ QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(pollfd, Q_PRIMITIVE_TYPE); -static inline constexpr clockid_t SteadyClockClockId = +static inline constexpr clockid_t QSteadyClockClockId = #if !defined(CLOCK_MONOTONIC) // we don't know how to set the monotonic clock CLOCK_REALTIME @@ -99,7 +100,7 @@ static inline constexpr clockid_t QWaitConditionClockId = // unknown why use of the monotonic clock causes failures CLOCK_REALTIME #else - SteadyClockClockId; + QSteadyClockClockId; #endif ; @@ -123,11 +124,6 @@ inline Duration timespecToChrono(timespec ts) noexcept return duration_cast(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec}); } -inline std::chrono::milliseconds timespecToChronoMs(timespec ts) noexcept -{ - return timespecToChrono(ts); -} - // Internal operator functions for timespecs constexpr inline timespec &normalizedTimespec(timespec &t) { @@ -141,39 +137,7 @@ constexpr inline timespec &normalizedTimespec(timespec &t) } return t; } -constexpr inline bool operator<(const timespec &t1, const timespec &t2) -{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); } -constexpr inline bool operator==(const timespec &t1, const timespec &t2) -{ return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; } -constexpr inline bool operator!=(const timespec &t1, const timespec &t2) -{ return !(t1 == t2); } -constexpr inline timespec &operator+=(timespec &t1, const timespec &t2) -{ - t1.tv_sec += t2.tv_sec; - t1.tv_nsec += t2.tv_nsec; - return normalizedTimespec(t1); -} -constexpr inline timespec operator+(const timespec &t1, const timespec &t2) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec + t2.tv_sec; - tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec; - return normalizedTimespec(tmp); -} -constexpr inline timespec operator-(const timespec &t1, const timespec &t2) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1); - tmp.tv_nsec = t1.tv_nsec - (t2.tv_nsec + OneSecAsNsecs); - return normalizedTimespec(tmp); -} -constexpr inline timespec operator*(const timespec &t1, int mul) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec * mul; - tmp.tv_nsec = t1.tv_nsec * mul; - return normalizedTimespec(tmp); -} + inline timeval timespecToTimeval(timespec ts) { timeval tv; @@ -182,43 +146,7 @@ inline timeval timespecToTimeval(timespec ts) return tv; } -inline timespec &operator+=(timespec &t1, std::chrono::milliseconds msecs) -{ - t1 += durationToTimespec(msecs); - return t1; -} - -inline timespec &operator+=(timespec &t1, int ms) -{ - t1 += std::chrono::milliseconds{ms}; - return t1; -} - -inline timespec operator+(const timespec &t1, std::chrono::milliseconds msecs) -{ - timespec tmp = t1; - tmp += msecs; - return tmp; -} - -inline timespec operator+(const timespec &t1, int ms) -{ - return t1 + std::chrono::milliseconds{ms}; -} - -inline timespec qAbsTimespec(timespec ts) -{ - if (ts.tv_sec < 0) { - ts.tv_sec = -ts.tv_sec - 1; - ts.tv_nsec -= OneSecAsNsecs; - } - if (ts.tv_sec == 0 && ts.tv_nsec < 0) { - ts.tv_nsec = -ts.tv_nsec; - } - return normalizedTimespec(ts); -} - -template +template inline timespec deadlineToAbstime(QDeadlineTimer deadline) { using namespace std::chrono; @@ -245,7 +173,13 @@ static inline int qt_safe_openat(int dfd, const char *pathname, int flags, mode_ { // everyone already has O_CLOEXEC int fd; +#ifdef Q_OS_REDOX + if (dfd != AT_FDCWD) + return -1; + QT_EINTR_LOOP(fd, QT_OPEN(pathname, flags | O_CLOEXEC, mode)); +#else QT_EINTR_LOOP(fd, openat(dfd, pathname, flags | O_CLOEXEC, mode)); +#endif return fd; } #endif diff --git a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qcore_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h.orig similarity index 80% rename from local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qcore_unix_p.h rename to local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h.orig index e94ffab8e7..f20561fc83 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/QtCore/private/qcore_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_unix_p.h.orig @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QCORE_UNIX_P_H #define QCORE_UNIX_P_H @@ -65,7 +66,7 @@ QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(pollfd, Q_PRIMITIVE_TYPE); -static inline constexpr clockid_t SteadyClockClockId = +static inline constexpr clockid_t QSteadyClockClockId = #if !defined(CLOCK_MONOTONIC) // we don't know how to set the monotonic clock CLOCK_REALTIME @@ -99,7 +100,7 @@ static inline constexpr clockid_t QWaitConditionClockId = // unknown why use of the monotonic clock causes failures CLOCK_REALTIME #else - SteadyClockClockId; + QSteadyClockClockId; #endif ; @@ -123,11 +124,6 @@ inline Duration timespecToChrono(timespec ts) noexcept return duration_cast(seconds{ts.tv_sec} + nanoseconds{ts.tv_nsec}); } -inline std::chrono::milliseconds timespecToChronoMs(timespec ts) noexcept -{ - return timespecToChrono(ts); -} - // Internal operator functions for timespecs constexpr inline timespec &normalizedTimespec(timespec &t) { @@ -141,39 +137,7 @@ constexpr inline timespec &normalizedTimespec(timespec &t) } return t; } -constexpr inline bool operator<(const timespec &t1, const timespec &t2) -{ return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec < t2.tv_nsec); } -constexpr inline bool operator==(const timespec &t1, const timespec &t2) -{ return t1.tv_sec == t2.tv_sec && t1.tv_nsec == t2.tv_nsec; } -constexpr inline bool operator!=(const timespec &t1, const timespec &t2) -{ return !(t1 == t2); } -constexpr inline timespec &operator+=(timespec &t1, const timespec &t2) -{ - t1.tv_sec += t2.tv_sec; - t1.tv_nsec += t2.tv_nsec; - return normalizedTimespec(t1); -} -constexpr inline timespec operator+(const timespec &t1, const timespec &t2) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec + t2.tv_sec; - tmp.tv_nsec = t1.tv_nsec + t2.tv_nsec; - return normalizedTimespec(tmp); -} -constexpr inline timespec operator-(const timespec &t1, const timespec &t2) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1); - tmp.tv_nsec = t1.tv_nsec - (t2.tv_nsec + OneSecAsNsecs); - return normalizedTimespec(tmp); -} -constexpr inline timespec operator*(const timespec &t1, int mul) -{ - timespec tmp = {}; - tmp.tv_sec = t1.tv_sec * mul; - tmp.tv_nsec = t1.tv_nsec * mul; - return normalizedTimespec(tmp); -} + inline timeval timespecToTimeval(timespec ts) { timeval tv; @@ -182,43 +146,7 @@ inline timeval timespecToTimeval(timespec ts) return tv; } -inline timespec &operator+=(timespec &t1, std::chrono::milliseconds msecs) -{ - t1 += durationToTimespec(msecs); - return t1; -} - -inline timespec &operator+=(timespec &t1, int ms) -{ - t1 += std::chrono::milliseconds{ms}; - return t1; -} - -inline timespec operator+(const timespec &t1, std::chrono::milliseconds msecs) -{ - timespec tmp = t1; - tmp += msecs; - return tmp; -} - -inline timespec operator+(const timespec &t1, int ms) -{ - return t1 + std::chrono::milliseconds{ms}; -} - -inline timespec qAbsTimespec(timespec ts) -{ - if (ts.tv_sec < 0) { - ts.tv_sec = -ts.tv_sec - 1; - ts.tv_nsec -= OneSecAsNsecs; - } - if (ts.tv_sec == 0 && ts.tv_nsec < 0) { - ts.tv_nsec = -ts.tv_nsec; - } - return normalizedTimespec(ts); -} - -template +template inline timespec deadlineToAbstime(QDeadlineTimer deadline) { using namespace std::chrono; diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_wasm.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_wasm.cpp index 8df2fe3e95..cedc929f16 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_wasm.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcore_wasm.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.cpp index 310b011a1c..8bad152483 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qcoreapplication.h" #include "qcoreapplication_p.h" @@ -45,6 +46,10 @@ #include #include +#ifdef Q_OS_WASM +#include +#endif + #if QT_CONFIG(permissions) #include #endif @@ -827,11 +832,11 @@ void Q_TRACE_INSTRUMENT(qtcore) QCoreApplicationPrivate::init() // into account. If necessary, recompute right away and replay the manual changes on top of the // new lib paths. if (coreappdata->libPathsInitialized()) { - const QStringList appPaths = std::move(coreappdata->app_libpaths); + const QStringList appPaths = std::exchange(coreappdata->app_libpaths, {}); Q_ASSERT(!coreappdata->libPathsInitialized()); if (coreappdata->libPathsManuallySet()) { - const QStringList manualPaths = std::move(coreappdata->manual_libpaths); + const QStringList manualPaths = std::exchange(coreappdata->manual_libpaths, {}); Q_ASSERT(!coreappdata->libPathsManuallySet()); // Replay the delta. As paths can only be prepended to the front or removed from @@ -1506,6 +1511,11 @@ void QCoreApplication::exit(int returnCode) { if (!self) return; + +#ifdef Q_OS_WASM + if (!qstdweb::haveAsyncify()) + qFatal("Terminating since we don't have asyncify"); +#endif QCoreApplicationPrivate *d = self->d_func(); if (!d->aboutToQuitEmitted) { emit self->aboutToQuit(QCoreApplication::QPrivateSignal()); diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.h index 054e53a4a4..711a00d3d8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QCOREAPPLICATION_H #define QCOREAPPLICATION_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_mac.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_mac.cpp index 982672caa5..497069c990 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_mac.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_mac.cpp @@ -1,10 +1,13 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qcoreapplication.h" #include "private/qcoreapplication_p.h" #include +#include + QT_BEGIN_NAMESPACE /***************************************************************************** @@ -13,14 +16,12 @@ QT_BEGIN_NAMESPACE QString qAppFileName() { // QCoreApplication::applicationFilePath() expects a canonical path - static QString appFileName; - if (appFileName.isEmpty()) { - QCFType bundleURL(CFBundleCopyExecutableURL(CFBundleGetMainBundle())); - if (bundleURL) { - QCFString cfPath(CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle)); - if (cfPath) - appFileName = cfPath; - } + QString appFileName; + QCFType bundleURL(CFBundleCopyExecutableURL(CFBundleGetMainBundle())); + if (bundleURL) { + QCFString cfPath(CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle)); + if (cfPath) + appFileName = QFileInfo(cfPath).canonicalFilePath(); } return appFileName; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_p.h index 0027b1ad57..9df2de0a8b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QCOREAPPLICATION_P_H #define QCOREAPPLICATION_P_H @@ -159,7 +160,6 @@ public: void processCommandLineArguments(); QString cachedApplicationFilePath; QString qmljs_debug_arguments; // a string containing arguments for js/qml debugging. - inline QString qmljsDebugArgumentsString() const { return qmljs_debug_arguments; } #ifdef QT_NO_QOBJECT QCoreApplication *q_ptr = nullptr; diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_platform.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_platform.h index 4bca99493a..a5153f6900 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_platform.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_platform.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QCOREAPPLICATION_PLATFORM_H #define QCOREAPPLICATION_PLATFORM_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_win.cpp index 45d6e2e3a2..cc13e3bb75 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreapplication_win.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2013 Samuel Gaist // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qcoreapplication.h" #include "qcoreapplication_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.cpp index 8b6e7c8326..ccca704392 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qcoreevent.h" #include "qcoreevent_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.h index 50367efd51..d7e3228d28 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QCOREEVENT_H #define QCOREEVENT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent_p.h index ac90baad9b..ad6caf57fd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qcoreevent_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef QCOREEVENT_P_H #define QCOREEVENT_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.cpp index 44e84b9bdd..8fc4883fe8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qdeadlinetimer.h" #include "private/qnumeric_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.h index 0933abd7ea..76ae3e20d5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qdeadlinetimer.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDEADLINETIMER_H #define QDEADLINETIMER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.cpp index c4308a0b8f..ec1440d30a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qelapsedtimer.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.h index e71573456d..f1f22d65c1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qelapsedtimer.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QELAPSEDTIMER_H #define QELAPSEDTIMER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_cf_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_cf_p.h index 3775439aeb..f8cbdca408 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_cf_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_cf_p.h @@ -1,5 +1,6 @@ // Copyright (c) 2007-2008, Apple, Inc. // SPDX-License-Identifier: BSD-3-Clause +// Qt-Security score:significant reason:default #ifndef QEVENTDISPATCHER_CF_P_H #define QEVENTDISPATCHER_CF_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib.cpp index 9aee6a96e0..2a98f40790 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qeventdispatcher_glib_p.h" #include "qeventdispatcher_unix_p.h" @@ -105,7 +106,7 @@ static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout) } auto remaining = src->timerList.timerWait().value_or(-1ms); - *timeout = q26::saturate_cast(ceil(remaining).count()); + *timeout = q26::saturating_cast(ceil(remaining).count()); return (*timeout == 0); } @@ -214,6 +215,7 @@ struct GPostEventSource GSource source; QAtomicInt serialNumber; int lastSerialNumber; + int pendingSerialNumber; QEventDispatcherGlibPrivate *d; }; @@ -242,8 +244,9 @@ static gboolean postEventSourceCheck(GSource *source) static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer) { GPostEventSource *source = reinterpret_cast(s); - source->lastSerialNumber = source->serialNumber.loadRelaxed(); + source->pendingSerialNumber = source->serialNumber.loadRelaxed(); QCoreApplication::sendPostedEvents(); + source->lastSerialNumber = source->pendingSerialNumber; source->d->runTimersOnceWithNormalPriority(); return true; // i dunno, george... } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib_p.h index 2376a7ed8b..ec9aa7d271 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QEVENTDISPATCHER_GLIB_P_H #define QEVENTDISPATCHER_GLIB_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix.cpp index 0cd12204ad..5612ce8533 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qplatformdefs.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix_p.h index 6596e998c9..54a9e7b8fe 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QEVENTDISPATCHER_UNIX_P_H #define QEVENTDISPATCHER_UNIX_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm.cpp index 07d35cf314..2f93224f59 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qeventdispatcher_wasm_p.h" @@ -46,7 +47,8 @@ static bool useAsyncify() #endif // defined(QT_STATIC) Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr; -Q_CONSTINIT std::shared_ptr QEventDispatcherWasm::g_mainThreadSuspendResumeControl; +Q_CONSTINIT std::shared_ptr QEventDispatcherWasm::g_customMainThreadSuspendResumeControl; +Q_CONSTINIT QWasmSuspendResumeControl *QEventDispatcherWasm::g_mainThreadSuspendResumeControl = nullptr; #if QT_CONFIG(thread) Q_CONSTINIT QVector QEventDispatcherWasm::g_secondaryThreadEventDispatchers; @@ -77,19 +79,20 @@ QEventDispatcherWasm::QEventDispatcherWasm(std::shared_ptr(); + g_mainThreadSuspendResumeControl = QWasmSuspendResumeControl::get(); } // Zero-timer used on wake() calls - m_wakeupTimer = std::make_unique(g_mainThreadSuspendResumeControl.get(), [](){ onWakeup(); }); + m_wakeupTimer = std::make_unique(g_mainThreadSuspendResumeControl, [](){ onWakeup(); }); // Timer set to fire at the next Qt timer timeout - m_nativeTimer = std::make_unique(g_mainThreadSuspendResumeControl.get(), []() { onTimer(); }); + m_nativeTimer = std::make_unique(g_mainThreadSuspendResumeControl, []() { onTimer(); }); // Timer used when suspending to process native events - m_suspendTimer = std::make_unique(g_mainThreadSuspendResumeControl.get(), []() { onProcessNativeEventsResume(); }); + m_suspendTimer = std::make_unique(g_mainThreadSuspendResumeControl, []() { onProcessNativeEventsResume(); }); } else { #if QT_CONFIG(thread) std::lock_guard lock(g_staticDataMutex); @@ -118,7 +121,8 @@ QEventDispatcherWasm::~QEventDispatcherWasm() { QWasmSocket::clearSocketNotifiers(); g_mainThreadEventDispatcher = nullptr; - g_mainThreadSuspendResumeControl.reset(); + g_customMainThreadSuspendResumeControl.reset(); + g_mainThreadSuspendResumeControl = nullptr; } } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm_p.h index 1946bf63ed..52dee48dd5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_wasm_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QEVENTDISPATCHER_WASM_P_H #define QEVENTDISPATCHER_WASM_P_H @@ -87,8 +88,8 @@ private: void updateNativeTimer(); static QEventDispatcherWasm *g_mainThreadEventDispatcher; - static std::shared_ptr g_mainThreadSuspendResumeControl; - + static std::shared_ptr g_customMainThreadSuspendResumeControl; + static QWasmSuspendResumeControl *g_mainThreadSuspendResumeControl; bool m_interrupted = false; bool m_wakeup = false; diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win.cpp index 30eef9ff35..c8842b97ab 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qeventdispatcher_win_p.h" @@ -349,10 +350,10 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) bool ok = false; ULONG tolerance = calculateNextTimeout(t, qt_msectime()); - uint interval = q26::saturate_cast(t->interval); + uint interval = q26::saturating_cast(t->interval); if (interval != t->interval) { // Now we'll need to post the timer event at each second timeout. - interval = q26::saturate_cast(t->interval / 2 + 1); + interval = q26::saturating_cast(t->interval / 2 + 1); t->usesExtendedInterval = true; t->isSecondTimeout = false; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win_p.h index 0efd4a8379..91f0e960dc 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventdispatcher_win_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QEVENTDISPATCHER_WIN_P_H #define QEVENTDISPATCHER_WIN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.cpp index 5350145aed..9f069b0ce5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qeventloop.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.h index ec79c07cd7..86d4ce0b68 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QEVENTLOOP_H #define QEVENTLOOP_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop_p.h index aa50b8c1d3..8f90843455 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qeventloop_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QEVENTLOOP_P_H #define QEVENTLOOP_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_p.h index 58afc207e6..06875f36f2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_p.h @@ -11,6 +11,7 @@ // // We mean it. // +// Qt-Security score:significant reason:default #ifndef QFUNCTIONS_P_H #define QFUNCTIONS_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win.cpp index 4c057cdb2c..36620aa8da 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qfunctions_win_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win_p.h index e8cc57cc84..52b3132a16 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_win_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QFUNCTIONS_WIN_P_H #define QFUNCTIONS_WIN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_winrt_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_winrt_p.h index 6c406961fd..f91f5bcafe 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_winrt_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qfunctions_winrt_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QFUNCTIONS_WINRT_P_H #define QFUNCTIONS_WINRT_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.cpp index b0b772d18e..ebf7b044ff 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.h index a5a5b35924..9069b3ed6c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QITERABLE_H #define QITERABLE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable_impl.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable_impl.h index 419595a3f2..c6af1c934a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qiterable_impl.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QITERABLE_IMPL_H #define QITERABLE_IMPL_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.h index 97d0cd3768..eb3824e99d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.h @@ -1,5 +1,6 @@ // Copyright (C) 2023 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 +// Qt-Security score:significant reason:default #ifndef QJNIARRAY_H #define QJNIARRAY_H @@ -903,7 +904,7 @@ auto QJniArrayBase::makeObjectArray(List &&list) return ResultType(); JNIEnv *env = QJniEnvironment::getJniEnv(); - const size_type length = q26::saturate_cast(std::size(list)); + const size_type length = q26::saturating_cast(std::size(list)); // this assumes that all objects in the list have the same class jclass elementClass = nullptr; diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.qdoc b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.qdoc index 41c4e5e9b8..f4718141e1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniarray.qdoc @@ -380,17 +380,38 @@ \endtable */ +/*! + \typedef QJniArray::iterator + + A random-access iterator for QJniArray. +/* + /*! \typedef QJniArray::const_iterator A random-access, const iterator for QJniArray. */ +/*! + \typedef QJniArray::reverse_iterator + + A reverse iterator for QJniArray, synonym for + \c{std::reverse_iterator}. + +//! [reverse_iterator-operator->] + \note Accessing the element of the reverse iterator using \c{operator->()} + requires C++20, as the C++17 reverse_iterator does not support iterators that + return a proxy object. +//! [reverse_iterator-operator->] +/* + /*! \typedef QJniArray::const_reverse_iterator A reverse iterator for the QJniArray, synonym for \c{std::reverse_iterator}. + + \include qjniarray.qdoc reverse_iterator-operator-> */ /*! @@ -431,6 +452,8 @@ If the array is \l{QJniArrayBase::isValid()}{invalid}, then this will return the same iterator as the corresponding rend() function. + \include qjniarray.qdoc reverse_iterator-operator-> + \sa rend(), begin() */ @@ -442,6 +465,8 @@ Returns an \l{STL-style iterators}{STL-style reverse iterator} pointing just after the last item in the list, in reverse order. + \include qjniarray.qdoc reverse_iterator-operator-> + \sa rbegin(), end() */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.cpp index 1ee658fd18..2a0ac80fdf 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qjnienvironment.h" #include "qjnihelpers_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.h index a5f3700b1f..58fab6a40a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnienvironment.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QJNI_ENVIRONMENT_H #define QJNI_ENVIRONMENT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers.cpp index 2e57a18847..9b08e54ceb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qjnihelpers_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers_p.h index 3a6e2e62ab..41eac802be 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnihelpers_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QJNIHELPERS_H #define QJNIHELPERS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.cpp index 21bfe5af44..afc31117e3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qjniobject.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.h index 9e6b86a7b8..6972f6ffd9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjniobject.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QJNIOBJECT_H #define QJNIOBJECT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes.h index 8ee367d188..c8f88acd1d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QJNITYPES_H #define QJNITYPES_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes_impl.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes_impl.h index 95e7aa5966..9597f6bdbd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qjnitypes_impl.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QJNITYPES_IMPL_H #define QJNITYPES_IMPL_H @@ -26,7 +27,7 @@ static inline jstring fromQString(const QString &string, JNIEnv *env) { if (!q20::in_range(string.size())) qWarning("String is too large for a Java string and will be truncated"); - const jsize length = q26::saturate_cast(string.size()); + const jsize length = q26::saturating_cast(string.size()); return env->NewString(reinterpret_cast(string.constData()), length); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.cpp index 8742a4bee5..cc317ebd20 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2013 Laszlo Papp // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.h index d5ba97c0fd..f738bb47b9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmath.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QMATH_H #define QMATH_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.cpp index 5eae6658a5..be05ae4a0b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.h index ab8bd9e136..023e462a3a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaassociation.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #ifndef QMETAASSOCIATION_H #define QMETAASSOCIATION_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.cpp index 6173198a97..c309270151 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qmetacontainer.h" #include "qmetatype.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.h index 66047afefd..3cf50680c7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetacontainer.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QMETACONTAINER_H #define QMETACONTAINER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.cpp index 24cc58829c..f7d739cf48 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2015 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qmetaobject.h" #include "qmetaobject_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.h index ff3cc751c3..6a976b877f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2014 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QMETAOBJECT_H #define QMETAOBJECT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject_p.h index bfda30fda2..e8510cd2c6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobject_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2014 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QMETAOBJECT_P_H #define QMETAOBJECT_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder.cpp index 9c198930f8..1e370fc2cd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qmetaobjectbuilder_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder_p.h index 9591944602..560ce8e1ac 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetaobjectbuilder_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QMETAOBJECTBUILDER_P_H #define QMETAOBJECTBUILDER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.cpp index 018dd61014..0d570c6ecd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.h index de52bd9830..25ca3329b9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetasequence.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #ifndef QMETASEQUENCE_H #define QMETASEQUENCE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.cpp index 34a22ee8a9..bc6719f585 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qmetatype.h" #include "qmetatype_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.h index fd11da0f00..2a520fc607 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype.h @@ -2,6 +2,7 @@ // Copyright (C) 2018 Intel Corporation. // Copyright (C) 2014 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QMETATYPE_H #define QMETATYPE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype_p.h index b39e1de0be..513b69194b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmetatype_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QMETATYPE_P_H #define QMETATYPE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.cpp index 1bb8bdb265..44d3d5e72a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:critical reason:data-parser #include "qmimedata.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.h index 0969a7315c..c3bab6dd18 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qmimedata.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:header-decls-only #ifndef QMIMEDATA_H #define QMIMEDATA_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.cpp index 15c2774464..45698a307b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.cpp @@ -2,6 +2,7 @@ // Copyright (C) 2016 Intel Corporation. // Copyright (C) 2013 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qobject.h" #include "qobject_p.h" @@ -4862,12 +4863,6 @@ QDebug operator<<(QDebug dbg, const QObject *o) in a QVariant, you can convert them to strings. Likewise, passing them to QDebug will print out their names. - Mind that the enum values are stored as signed \c int in the meta object system. - Registering enumerations with values outside the range of values valid for \c int - will lead to overflows and potentially undefined behavior when accessing them through - the meta object system. QML, for example, does access registered enumerations through - the meta object system. - \sa {Qt's Property System} */ @@ -4929,12 +4924,6 @@ QDebug operator<<(QDebug dbg, const QObject *o) used in a QVariant, you can convert them to strings. Likewise, passing them to QDebug will print out their names. - Mind that the enum values are stored as signed \c int in the meta object system. - Registering enumerations with values outside the range of values valid for \c int - will lead to overflows and potentially undefined behavior when accessing them through - the meta object system. QML, for example, does access registered enumerations through - the meta object system. - \sa {Qt's Property System} */ @@ -5572,7 +5561,7 @@ bool QObject::disconnect(const QMetaObject::Connection &connection) if (!c) return false; const bool disconnected = QObjectPrivate::removeConnection(c); - const_cast(connection).d_ptr = nullptr; + connection.d_ptr = nullptr; c->deref(); // has been removed from the QMetaObject::Connection object return disconnected; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.h index 110eae9b69..dd0ed4f98d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2013 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QOBJECT_H #define QOBJECT_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_impl.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_impl.h index 34e6bd84f3..1c27e5fbc7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_impl.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QOBJECT_H #error Do not include qobject_impl.h directly diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p.h index 72d00ead76..031fef3c7b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2013 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QOBJECT_P_H #define QOBJECT_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p_p.h index fdc0f1e839..dee71643b8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobject_p_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2013 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QOBJECT_P_P_H #define QOBJECT_P_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.cpp index 48210ede8e..c77ffbddb0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qobjectcleanuphandler.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.h index b01ed94d47..c19e62bd70 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectcleanuphandler.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QOBJECTCLEANUPHANDLER_H #define QOBJECTCLEANUPHANDLER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs.h index 848102cc57..776c095b55 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2019 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QOBJECTDEFS_H #define QOBJECTDEFS_H @@ -671,6 +672,7 @@ private: }; class Q_CORE_EXPORT QMetaObject::Connection { + mutable // QTBUG-144929 void *d_ptr; //QObjectPrivate::Connection* explicit Connection(void *data) : d_ptr(data) { } friend class QObject; diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs_impl.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs_impl.h index 1b60596888..e3d3d3dd67 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qobjectdefs_impl.h @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2013 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QOBJECTDEFS_H #error Do not include qobjectdefs_impl.h directly diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.cpp index 69383dafdd..2c5c3778a1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qpermissions.h" #include "qpermissions_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.h index 9573e377e5..b3760dc133 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QPERMISSIONS_H #define QPERMISSIONS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_android.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_android.cpp index ded6c7ec8f..e457e3d763 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_android.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_android.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qpermissions.h" #include "qpermissions_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_p.h index 8838b36d9a..aeaa2b0913 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QPERMISSIONS_P_H #define QPERMISSIONS_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_wasm.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_wasm.cpp index 11bd4e864f..dcfdbd4607 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_wasm.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpermissions_wasm.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include #include @@ -135,8 +136,19 @@ namespace return cb(Qt::PermissionStatus::Denied); qstdweb::PromiseCallbacks queryCallbacks; - queryCallbacks.thenFunc = [device, cb](val) + queryCallbacks.thenFunc = [device, cb](val stream) { + // turn stream/light off + if (!stream.isNull() && !stream.isUndefined() && !stream["getTracks"].isUndefined()) { + emscripten::val tracks = stream.call("getTracks"); + if (!tracks.isUndefined() && tracks["length"].as() > 0) { + for (int i = 0; i < tracks["length"].as(); i++) { + tracks[i].call("stop"); + } + } + } + stream = emscripten::val::null(); // this causes the garbage collection to turn off media light + updatePermission(device, wapiGranted, cb); }; queryCallbacks.catchFunc = [device, cb](val error) @@ -149,8 +161,8 @@ namespace val constraint = val::object(); if (device == wapiCamera) constraint.set("video", true); - else - constraint.set("audio", true); + + constraint.set("audio", true); qstdweb::Promise::make(mediaDevices, QStringLiteral("getUserMedia"), queryCallbacks, constraint); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpointer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpointer.h index d876c8d761..2a7fb77442 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpointer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpointer.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QPOINTER_H #define QPOINTER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll.cpp index 58fb0234b4..ae73df5a77 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qcore_unix_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll_p.h index 7c7fa7a5a3..5cc55bf474 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpoll_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QPOLL_P_H #define QPOLL_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.cpp index 56013380aa..202199941d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qproperty.h" #include "qproperty_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.h index 9929b9c9bb..ec0f8a9d3e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QPROPERTY_H #define QPROPERTY_H @@ -715,6 +716,17 @@ QUntypedPropertyBinding makeBinding(const QUntypedPropertyData *d, template inline constexpr QBindableInterface iface = { +#ifdef QT_NO_DATA_RELOCATION + // On windows the address of a dllimported function can't be relocated here. + // MSVC automatically generates a trampoline, but clang won't, so do it explicitly. + [](const QUntypedPropertyData *d, void *value) { getter(d, value); }, + [](QUntypedPropertyData *d, const void *value) { setter(d, value); }, + [](const QUntypedPropertyData *d) -> QUntypedPropertyBinding { return getBinding(d); }, + &setBinding, + &makeBinding, + [](const QUntypedPropertyData *d, QPropertyObserver *observer) { setObserver(d, observer); }, + &QMetaType::fromType, +#else &getter, &setter, &getBinding, @@ -722,6 +734,7 @@ inline constexpr QBindableInterface iface = { &makeBinding, &setObserver, &QMetaType::fromType, +#endif }; } } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty_p.h index 30b692c45a..784184b475 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qproperty_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QPROPERTY_P_H #define QPROPERTY_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpropertyprivate.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpropertyprivate.h index 785a179315..bbdcd5f444 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qpropertyprivate.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qpropertyprivate.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QPROPERTYPRIVATE_H #define QPROPERTYPRIVATE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.cpp index cf9c38c533..ba94cea55e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.h index 4649588b28..f4e889635b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsequentialiterable.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QSEQUENTIALITERABLE_H #define QSEQUENTIALITERABLE_H @@ -123,6 +124,10 @@ public: void removeValue(Position position = Unspecified); QMetaType valueMetaType() const; + + // Random access iteration is broken on QSequentialIterator. + // That's why this class is deprecated after all. + constexpr bool canRandomAccessIterate() const { return false; } }; template<> diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.cpp index 96e909d1be..5e5095ced0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qglobal.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.h index af0be52ee5..3925b69143 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsignalmapper.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QSIGNALMAPPER_H #define QSIGNALMAPPER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer.cpp index d0ebe66d9e..9bda5e245f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer_p.h index bdc02ab0b8..a40c8684e6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsingleshottimer_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QSINGLESHOTTIMER_P_H #define QSINGLESHOTTIMER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.cpp index 8d7e0a18f3..559cfd017f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #define BUILDING_QSOCKETNOTIFIER #include "qsocketnotifier.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.h index ac9e577ebc..d80b123c02 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsocketnotifier.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QSOCKETNOTIFIER_H #define QSOCKETNOTIFIER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror.cpp index 6274115014..c4ccd4fd39 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include #include "qsystemerror_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror_p.h index 72ced63dc5..16b3818b76 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qsystemerror_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QSYSTEMERROR_P_H #define QSYSTEMERROR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.cpp index c0c24d9db8..9bbe1c18e8 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qtestsupport_core.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.h index 50e08f2df4..c5a85b4e08 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtestsupport_core.h @@ -1,5 +1,6 @@ // Copyright (C) 2018 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 +// Qt-Security score:significant reason:default #ifndef QTESTSUPPORT_CORE_H #define QTESTSUPPORT_CORE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.cpp index 319ae8bc24..811040aa7c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qtimer.h" #include "qtimer_p.h" @@ -259,7 +260,7 @@ checkInterval(const char *caller, std::chrono::milliseconds interval) } const auto msec = interval.count(); - int ret = q26::saturate_cast(msec); + int ret = q26::saturating_cast(msec); if (ret != msec) { qWarning("%s: interval exceeds maximum allowed interval, it will be clamped to " "INT_MAX ms (about 24 days).", caller); @@ -708,7 +709,7 @@ int QTimer::remainingTime() const using namespace std::chrono; auto remaining = QAbstractEventDispatcher::instance()->remainingTime(d->id); const auto msec = ceil(remaining).count(); - const int ret = q26::saturate_cast(msec); + const int ret = q26::saturating_cast(msec); Q_ASSERT(ret == msec); // cannot overflow because the interval is clamped before it's set return ret; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.h index 7f14d3803c..c8879fede7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QTIMER_H #define QTIMER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer_p.h index 91d6234665..5fe5f62626 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimer_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QTIMER_P_H #define QTIMER_P_H // diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix.cpp index cce55171f2..7daa01e9a6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix_p.h index 293e9c4d4e..67ee60787c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtimerinfo_unix_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QTIMERINFO_UNIX_P_H #define QTIMERINFO_UNIX_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtmetamacros.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtmetamacros.h index 2102575ce3..58363ef214 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qtmetamacros.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qtmetamacros.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 Olivier Goffart // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTMETAMACROS_H #define QTMETAMACROS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.cpp index 8318bb1a2d..098109d827 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.cpp @@ -155,10 +155,13 @@ static std::optional qConvertToNumber(const QVariant::Private *d, boo case QMetaType::UShort: case QMetaType::ULong: return qlonglong(qMetaTypeUNumber(d)); + case QMetaType::QCborSimpleType: + return qToUnderlying(d->get()); } - if (d->typeInterface()->flags & QMetaType::IsEnumeration - || d->typeInterface()->typeId == QMetaType::QCborSimpleType) + if (d->typeInterface()->flags & QMetaType::IsUnsignedEnumeration) + return qMetaTypeUNumber(d); + if (d->typeInterface()->flags & QMetaType::IsEnumeration) return qMetaTypeNumberBySize(d); return std::nullopt; @@ -923,67 +926,69 @@ QVariant::QVariant(QMetaType type, const void *copy) { } -QVariant::QVariant(int val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(uint val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(qlonglong val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(qulonglong val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(bool val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(double val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(float val) noexcept : d(std::piecewise_construct_t{}, val) {} +#define MAKE_CTOR_BY_VALUE(...) \ + QVariant::QVariant(__VA_ARGS__ val) \ + noexcept(QVariant::Private::CanUseInternalSpace<__VA_ARGS__>) \ + : d{std::in_place, std::move(val)} {} \ + static_assert(std::is_nothrow_copy_constructible_v<__VA_ARGS__>) \ + /* end */ -QVariant::QVariant(const QByteArray &val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(const QBitArray &val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(const QString &val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(QChar val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(const QStringList &val) noexcept : d(std::piecewise_construct_t{}, val) {} +MAKE_CTOR_BY_VALUE(int); +MAKE_CTOR_BY_VALUE(uint); +MAKE_CTOR_BY_VALUE(qlonglong); +MAKE_CTOR_BY_VALUE(qulonglong); +MAKE_CTOR_BY_VALUE(bool); +MAKE_CTOR_BY_VALUE(double); +MAKE_CTOR_BY_VALUE(float); -QVariant::QVariant(QDate val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(QTime val) noexcept : d(std::piecewise_construct_t{}, val) {} -QVariant::QVariant(const QDateTime &val) noexcept : d(std::piecewise_construct_t{}, val) {} +QVariant::QVariant(const QByteArray &val) noexcept : d{std::in_place, val} {} +QVariant::QVariant(const QBitArray &val) noexcept : d{std::in_place, val} {} +QVariant::QVariant(const QString &val) noexcept : d{std::in_place, val} {} +MAKE_CTOR_BY_VALUE(QChar); +QVariant::QVariant(const QStringList &val) noexcept : d{std::in_place, val} {} -QVariant::QVariant(const QList &list) noexcept : d(std::piecewise_construct_t{}, list) {} -QVariant::QVariant(const QMap &map) noexcept : d(std::piecewise_construct_t{}, map) {} -QVariant::QVariant(const QHash &hash) noexcept : d(std::piecewise_construct_t{}, hash) {} +MAKE_CTOR_BY_VALUE(QDate); +MAKE_CTOR_BY_VALUE(QTime); +QVariant::QVariant(const QDateTime &val) noexcept : d{std::in_place, val} {} + +QVariant::QVariant(const QList &list) noexcept : d{std::in_place, list} {} +QVariant::QVariant(const QMap &map) noexcept : d{std::in_place, map} {} +QVariant::QVariant(const QHash &hash) noexcept : d{std::in_place, hash} {} QVariant::QVariant(QLatin1StringView val) : QVariant(QString(val)) {} #if QT_CONFIG(easingcurve) -QVariant::QVariant(const QEasingCurve &val) : d(std::piecewise_construct_t{}, val) {} +QVariant::QVariant(const QEasingCurve &val) : d{std::in_place, val} {} #endif -QVariant::QVariant(QPoint pt) noexcept - : d(std::piecewise_construct_t{}, pt) {} -QVariant::QVariant(QPointF pt) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, pt) {} -QVariant::QVariant(QRect r) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, r) {} -QVariant::QVariant(QRectF r) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, r) {} -QVariant::QVariant(QLine l) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, l) {} -QVariant::QVariant(QLineF l) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, l) {} -QVariant::QVariant(QSize s) noexcept - : d(std::piecewise_construct_t{}, s) {} -QVariant::QVariant(QSizeF s) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, s) {} -QVariant::QVariant(const QUrl &u) noexcept : d(std::piecewise_construct_t{}, u) {} -QVariant::QVariant(const QLocale &l) noexcept : d(std::piecewise_construct_t{}, l) {} +MAKE_CTOR_BY_VALUE(QPoint); +MAKE_CTOR_BY_VALUE(QPointF); +MAKE_CTOR_BY_VALUE(QRect); +MAKE_CTOR_BY_VALUE(QRectF); +MAKE_CTOR_BY_VALUE(QLine); +MAKE_CTOR_BY_VALUE(QLineF); +MAKE_CTOR_BY_VALUE(QSize); +MAKE_CTOR_BY_VALUE(QSizeF); +QVariant::QVariant(const QUrl &u) noexcept : d{std::in_place, u} {} +QVariant::QVariant(const QLocale &l) noexcept : d{std::in_place, l} {} #if QT_CONFIG(regularexpression) -QVariant::QVariant(const QRegularExpression &re) noexcept : d(std::piecewise_construct_t{}, re) {} +QVariant::QVariant(const QRegularExpression &re) noexcept : d{std::in_place, re} {} #endif // QT_CONFIG(regularexpression) -QVariant::QVariant(QUuid uuid) noexcept(Private::FitsInInternalSize<16>) : d(std::piecewise_construct_t{}, uuid) {} +MAKE_CTOR_BY_VALUE(QUuid); QVariant::QVariant(const QJsonValue &jsonValue) noexcept(Private::FitsInInternalSize) - : d(std::piecewise_construct_t{}, jsonValue) + : d{std::in_place, jsonValue} { static_assert(sizeof(CborValueStandIn) == sizeof(QJsonValue)); } -QVariant::QVariant(const QJsonObject &jsonObject) noexcept : d(std::piecewise_construct_t{}, jsonObject) {} -QVariant::QVariant(const QJsonArray &jsonArray) noexcept : d(std::piecewise_construct_t{}, jsonArray) {} -QVariant::QVariant(const QJsonDocument &jsonDocument) : d(std::piecewise_construct_t{}, jsonDocument) {} +QVariant::QVariant(const QJsonObject &jsonObject) noexcept : d{std::in_place, jsonObject} {} +QVariant::QVariant(const QJsonArray &jsonArray) noexcept : d{std::in_place, jsonArray} {} +QVariant::QVariant(const QJsonDocument &jsonDocument) : d{std::in_place, jsonDocument} {} #if QT_CONFIG(itemmodel) QVariant::QVariant(const QModelIndex &modelIndex) noexcept(Private::FitsInInternalSize<8 + 2 * sizeof(quintptr)>) - : d(std::piecewise_construct_t{}, modelIndex) {} -QVariant::QVariant(const QPersistentModelIndex &modelIndex) : d(std::piecewise_construct_t{}, modelIndex) {} + : d{std::in_place, modelIndex} {} +QVariant::QVariant(const QPersistentModelIndex &modelIndex) + : d{std::in_place, modelIndex} {} #endif +#undef MAKE_CTOR_BY_VALUE + /*! \fn QVariant::Type QVariant::type() const \deprecated [6.0] Use typeId() or metaType() instead. @@ -2266,13 +2271,14 @@ static int numericTypePromotion(const QtPrivate::QMetaTypeInterface *iface1, if (qIsFloatingPoint(t1) || qIsFloatingPoint(t2)) return QMetaType::QReal; - auto isUnsigned = [](uint tp) { + auto isUnsigned = [](uint tp, const QtPrivate::QMetaTypeInterface *iface) { // only types for which sizeof(T) >= sizeof(int); lesser ones promote to int return tp == QMetaType::ULongLong || tp == QMetaType::ULong || - tp == QMetaType::UInt || tp == QMetaType::Char32; + tp == QMetaType::UInt || tp == QMetaType::Char32 || + (iface->flags & QMetaType::IsUnsignedEnumeration && iface->size >= sizeof(int)); }; - bool isUnsigned1 = isUnsigned(t1); - bool isUnsigned2 = isUnsigned(t2); + bool isUnsigned1 = isUnsigned(t1, iface1); + bool isUnsigned2 = isUnsigned(t2, iface2); // integral rules: // 1) if either type is a 64-bit unsigned, compare as 64-bit unsigned diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.h index 4f2e027493..7c5ebaf061 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant.h @@ -122,7 +122,11 @@ public: constexpr Private() noexcept : is_shared(false), is_null(true), packedType(0) {} explicit Private(const QtPrivate::QMetaTypeInterface *iface) noexcept; - template explicit Private(std::piecewise_construct_t, const T &t); + template + explicit Private(std::in_place_t, T &&t); + template + explicit Private(std::piecewise_construct_t, const T &t) + : Private{std::in_place, t} {} const void *storage() const { return is_shared ? data.shared->data() : &data.data; } @@ -792,37 +796,51 @@ private: QDebug qdebugHelper(QDebug) const; #endif + template static constexpr + bool canGetTypeFromVariant(Variant *v) noexcept + { + if (!v) + return false; + if (std::is_const_v && v->d.is_null) + return false; // (const) data() will not detach from is_null + return v->d.type() == QMetaType::fromType(); + } + + template T *typedData() + { + Q_PRE(canGetTypeFromVariant(this)); + return static_cast(data()); // detaches if necessary + } + + template const T *typedData() const + { + Q_PRE(canGetTypeFromVariant(this)); + return &d.get(); + } + template friend T *get_if(QVariant *v) noexcept { - // data() will detach from is_null, returning non-nullptr - if (!v || v->d.type() != QMetaType::fromType()) + if (!canGetTypeFromVariant(v)) return nullptr; - return static_cast(v->data()); + return v->typedData(); } template friend const T *get_if(const QVariant *v) noexcept { - // (const) data() will not detach from is_null, return nullptr - if (!v || v->d.is_null || v->d.type() != QMetaType::fromType()) + if (!canGetTypeFromVariant(v)) return nullptr; - return static_cast(v->data()); + return v->typedData(); } -#define Q_MK_GET(cvref) \ - template \ - friend T cvref get(QVariant cvref v) \ - { \ - if constexpr (std::is_const_v) \ - Q_ASSERT(!v.d.is_null); \ - Q_ASSERT(v.d.type() == QMetaType::fromType>()); \ - return static_cast(*get_if(&v)); \ - } \ +#define Q_MK_GET(CONST, REF) \ + template friend CONST T REF get(CONST QVariant REF v) \ + { return static_cast(*v.typedData()); } \ /* end */ - Q_MK_GET(&) - Q_MK_GET(const &) - Q_MK_GET(&&) - Q_MK_GET(const &&) + Q_MK_GET(, &) + Q_MK_GET(const, &) + Q_MK_GET(, &&) + Q_MK_GET(const, &&) #undef Q_MK_GET static QVariant moveConstruct(QMetaType type, void *data); diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant_p.h index 3ffa2c3635..6aecdae643 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariant_p.h @@ -80,27 +80,29 @@ inline QVariant::Private::Private(const QtPrivate::QMetaTypeInterface *iface) no Q_ASSERT((quintptr(iface) & 0x3) == 0); } -template inline -QVariant::Private::Private(std::piecewise_construct_t, const T &t) - : is_shared(!CanUseInternalSpace), is_null(std::is_same_v) +template +QVariant::Private::Private(std::in_place_t, TT &&t) + : is_shared{!CanUseInternalSpace>}, + is_null{std::is_null_pointer_v>} { + using T = q20::remove_cvref_t; // confirm noexceptness - static constexpr bool isNothrowQVariantConstructible = noexcept(QVariant(t)); - static constexpr bool isNothrowCopyConstructible = std::is_nothrow_copy_constructible_v; - static constexpr bool isNothrowCopyAssignable = std::is_nothrow_copy_assignable_v; + constexpr bool isNothrowQVariantConstructible = noexcept(QVariant{std::forward(t)}); + constexpr bool isNothrowConstructible = std::is_nothrow_constructible_v; + constexpr bool isNothrowAssignable = std::is_nothrow_assignable_v; const QtPrivate::QMetaTypeInterface *iface = QtPrivate::qMetaTypeInterfaceForType(); Q_ASSERT((quintptr(iface) & 0x3) == 0); packedType = quintptr(iface) >> 2; if constexpr (CanUseInternalSpace) { - static_assert(isNothrowQVariantConstructible == isNothrowCopyConstructible); - static_assert(isNothrowQVariantConstructible == isNothrowCopyAssignable); - new (data.data) T(t); + static_assert(isNothrowQVariantConstructible == isNothrowConstructible); + static_assert(isNothrowQVariantConstructible == isNothrowAssignable); + new (data.data) T(std::forward(t)); } else { static_assert(!isNothrowQVariantConstructible); // we allocate memory, even if T doesn't - data.shared = customConstructShared(sizeof(T), alignof(T), [=](void *where) { - new (where) T(t); + data.shared = customConstructShared(sizeof(T), alignof(T), [&t](void *where) { + new (where) T(std::forward(t)); }); } } diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvarianthash.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvarianthash.h index a36efc6e9a..a894f2f8c7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvarianthash.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvarianthash.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QVARIANTHASH_H #define QVARIANTHASH_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantlist.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantlist.h index 5a567854e8..20d84ee42d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantlist.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantlist.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QVARIANTLIST_H #define QVARIANTLIST_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantmap.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantmap.h index 22cb975b5c..8bf33abed7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantmap.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qvariantmap.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QVARIANTMAP_H #define QVARIANTMAP_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.cpp b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.cpp index afbf4227dc..e8f3689a2d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qwineventnotifier_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.h index f79be0197c..f989a76fa2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QWINEVENTNOTIFIER_H #define QWINEVENTNOTIFIER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier_p.h b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier_p.h index 3f78f55e61..c62d78527e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/kernel/qwineventnotifier_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #ifndef QWINEVENTNOTIFIER_P_H #define QWINEVENTNOTIFIER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern.cpp b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern.cpp index 7fed6091cf..ee800f60ad 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern.cpp @@ -102,13 +102,10 @@ QMimeGlobPattern::PatternType QMimeGlobPattern::detectPatternType(QStringView pa \sa QMimeType, QMimeDatabase, QMimeMagicRuleMatcher, QMimeMagicRule */ -bool QMimeGlobPattern::matchFileName(const QString &inputFileName) const +bool QMimeGlobPattern::matchFileName(const QString &fileName) const { // "Applications MUST match globs case-insensitively, except when the case-sensitive // attribute is set to true." - // The constructor takes care of putting case-insensitive patterns in lowercase. - const QString fileName = m_caseSensitivity == Qt::CaseInsensitive - ? inputFileName.toLower() : inputFileName; const qsizetype patternLength = m_pattern.size(); if (!patternLength) @@ -119,43 +116,37 @@ bool QMimeGlobPattern::matchFileName(const QString &inputFileName) const case SuffixPattern: { if (fileNameLength + 1 < patternLength) return false; - - const QChar *c1 = m_pattern.unicode() + patternLength - 1; - const QChar *c2 = fileName.unicode() + fileNameLength - 1; - int cnt = 1; - while (cnt < patternLength && *c1-- == *c2--) - ++cnt; - return cnt == patternLength; + // m_pattern is *.txt, skip the * + return fileName.endsWith(QStringView(m_pattern).mid(1), m_caseSensitivity); } case PrefixPattern: { if (fileNameLength + 1 < patternLength) return false; - - const QChar *c1 = m_pattern.unicode(); - const QChar *c2 = fileName.unicode(); - int cnt = 1; - while (cnt < patternLength && *c1++ == *c2++) - ++cnt; - return cnt == patternLength; + // m_pattern ends with *, stop just before + return fileName.startsWith(QStringView(m_pattern).chopped(1), m_caseSensitivity); } case LiteralPattern: - return (m_pattern == fileName); + return m_pattern.compare(fileName, m_caseSensitivity) == 0; case VdrPattern: // "[0-9][0-9][0-9].vdr" case return fileNameLength == 7 && fileName.at(0).isDigit() && fileName.at(1).isDigit() && fileName.at(2).isDigit() - && QStringView{fileName}.mid(3, 4) == ".vdr"_L1; + && QStringView{fileName}.mid(3, 4).compare(".vdr"_L1, m_caseSensitivity) == 0; case AnimPattern: { // "*.anim[1-9j]" case if (fileNameLength < 6) return false; - const QChar lastChar = fileName.at(fileNameLength - 1); + QChar lastChar = fileName.at(fileNameLength - 1); + if (m_caseSensitivity == Qt::CaseInsensitive) + lastChar = lastChar.toLower(); const bool lastCharOK = (lastChar.isDigit() && lastChar != u'0') || lastChar == u'j'; - return lastCharOK && QStringView{fileName}.mid(fileNameLength - 6, 5) == ".anim"_L1; + return lastCharOK && QStringView{fileName}.mid(fileNameLength - 6, 5).compare(".anim"_L1, m_caseSensitivity) == 0; } case OtherPattern: // Other fallback patterns: slow but correct method #if QT_CONFIG(regularexpression) auto rx = QRegularExpression::fromWildcard(m_pattern); + if (m_caseSensitivity == Qt::CaseInsensitive) + rx.setPatternOptions(QRegularExpression::CaseInsensitiveOption); return rx.match(fileName).hasMatch(); #else return false; diff --git a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern_p.h b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern_p.h index 27e9d377fa..bd7f6fab8d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimeglobpattern_p.h @@ -66,7 +66,7 @@ public: qSwap(m_patternType, other.m_patternType); } - bool matchFileName(const QString &inputFileName) const; + bool matchFileName(const QString &fileName) const; inline const QString &pattern() const { return m_pattern; } inline unsigned weight() const { return m_weight; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimetype.cpp b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimetype.cpp index b69937bd55..acc429e962 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimetype.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/mimetypes/qmimetype.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qmimetype.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras.cpp index 34d5a326fb..3f97885eb9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qandroidextras_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras_p.h index dcc6169e51..3088798a29 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidextras_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QANDROIDEXTRAS_H #define QANDROIDEXTRAS_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy.cpp index 1ad34baa85..49f8ecdf53 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy_p.h index fdcbed86f0..c84cd6d240 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroiditemmodelproxy_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QANDROIDITEMMODELPROXY_P_H #define QANDROIDITEMMODELPROXY_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy.cpp index 243f751db2..0d1c73d983 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy_p.h index ec13923208..384badc66a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidmodelindexproxy_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QANDROIDMODELINDEXPROXY_P_H #define QANDROIDMODELINDEXPROXY_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidnativeinterface.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidnativeinterface.cpp index 5771d28f3a..d6c8ca7858 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidnativeinterface.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidnativeinterface.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypeconverter_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypeconverter_p.h index 22ec20146b..7fe44106eb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypeconverter_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypeconverter_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QANDROIDTYPECONVERTER_P_H #define QANDROIDTYPECONVERTER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypes_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypes_p.h index e2c25f6965..d626828c95 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypes_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/android/qandroidtypes_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QANDROIDTYPES_P_H #define QANDROIDTYPES_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p.h index 03530133ad..2aaeb1d8f4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QDARWINPERMISSIONPLUGIN_P_H #define QDARWINPERMISSIONPLUGIN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h index ad4877d5d0..2403b12b66 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QDARWINPERMISSIONPLUGIN_P_P_H #define QDARWINPERMISSIONPLUGIN_P_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb.cpp index bbaf2c442a..194251b550 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb.cpp @@ -482,7 +482,6 @@ size_t qstdweb::Promise::State::s_numInstances = 0; Promise& Promise::addThenFunction(std::function thenFunc) { QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); m_state->m_handlers.push_back(suspendResume->registerEventHandler(thenFunc)); m_state->m_promise = @@ -498,7 +497,6 @@ Promise& Promise::addThenFunction(std::function thenFunc) Promise& Promise::addCatchFunction(std::function catchFunc) { QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); m_state->m_handlers.push_back(suspendResume->registerEventHandler(catchFunc)); m_state->m_promise = @@ -514,7 +512,6 @@ Promise& Promise::addCatchFunction(std::function catchFun Promise& Promise::addFinallyFunction(std::function finallyFunc) { QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); auto thisHandler = std::make_shared((uint32_t)(-1)); auto state = m_state; @@ -530,7 +527,6 @@ Promise& Promise::addFinallyFunction(std::function finallyFunc) if (state->m_handlers.back() == *thisHandler) { auto guard = state; // removeEventHandler will remove also this function QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); for (int i = 0; i < guard->m_handlers.size(); ++i) { suspendResume->removeEventHandler(guard->m_handlers[i]); guard->m_handlers[i] = (uint32_t)(-1); @@ -565,7 +561,6 @@ uint32_t Promise::adoptPromise(emscripten::val promise, PromiseCallbacks callbac "Promise::adoptPromise", "must provide at least one callback function"); QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); // Registers a possibly-empty callback with suspendresumecontrol. Returns // the the handler index if there was a valid callback, or nullopt. @@ -586,7 +581,8 @@ uint32_t Promise::adoptPromise(emscripten::val promise, PromiseCallbacks callbac auto finallyFunc = callbacks.finallyFunc; // 'Finally' callback which performs clean-up and calls the user-provided finally. - auto finally = [suspendResume, thenIndex, catchIndex, finallyIndex, finallyFunc](emscripten::val){ + auto finally = [thenIndex, catchIndex, finallyIndex, finallyFunc](emscripten::val){ + QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); // Clean up event handlers if (thenIndex) @@ -629,7 +625,6 @@ uint32_t Promise::adoptPromise(emscripten::val promise, PromiseCallbacks callbac void Promise::suspendExclusive(QList handlerIndices) { QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); suspendResume->suspendExclusive(handlerIndices); suspendResume->sendPendingEvents(); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb_p.h index 07df021c44..2d24efe7ab 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qstdweb_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QSTDWEB_P_H #define QSTDWEB_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver.cpp index ab0c8240dd..1e2b812e0e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #include "qwasmanimationdriver_p.h" #include "qwasmsuspendresumecontrol_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver_p.h index f8435c17a9..ad68826bc5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmanimationdriver_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #ifndef QWASMANIMATIONDRIVER_P_H #define QWASMANIMATIONDRIVER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal.cpp index 5ac4bd51c8..2c739e94f7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #include #include "qwasmglobal_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal_p.h index ee3f4e7142..5d8068b053 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmglobal_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QWASMGLOBAL_P_H #define QWASMGLOBAL_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine.cpp index 58e662d5fd..0e41bca1fc 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 Qt Group // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qwasmlocalfileengine_p.h" #include #include @@ -281,7 +282,9 @@ QAbstractFileEngine::FileFlags QWasmFileEngine::fileFlags(FileFlags type) const return type & (QAbstractFileEngine::FileFlag::ExistsFlag | QAbstractFileEngine::FileFlag::FileType | QAbstractFileEngine::FileFlag::ReadOwnerPerm | - QAbstractFileEngine::FileFlag::WriteOwnerPerm); + QAbstractFileEngine::FileFlag::WriteOwnerPerm | + QAbstractFileEngine::FileFlag::ReadUserPerm | + QAbstractFileEngine::FileFlag::WriteUserPerm); } bool QWasmFileEngine::setPermissions(uint perms) diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine_p.h index dd82788dd9..05d2cd8d0b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmlocalfileengine_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 Qt Group // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QWASMLOCALFILEENGINE_P_H #define QWASMLOCALFILEENGINE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket.cpp index 483650ce2d..d89d064953 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #include "qwasmsocket_p.h" #include "qwasmglobal_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket_p.h index da2ef94cdf..1476f64d75 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsocket_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QWASMSOCKET_P_H #define QWASMSOCKET_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp index 916a743619..b88f6082db 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #include "qwasmsuspendresumecontrol_p.h" #include "qstdweb_p.h" #include +#include #include #include @@ -39,7 +41,7 @@ using emscripten::val; event handlers directly in that case. */ -QWasmSuspendResumeControl *QWasmSuspendResumeControl::s_suspendResumeControl = nullptr; +Q_GLOBAL_STATIC(QWasmSuspendResumeControl, s_suspendResumeControl); // Setup/constructor function for Module.suspendResumeControl. // FIXME if assigning to the Module object from C++ is/becomes possible @@ -112,6 +114,7 @@ void qtRegisterEventHandlerJs(int index) { // Handle the event based on instance state and asyncify flag if (control.exclusiveEventHandler > 0) { // In exclusive mode, resume on exclusive event handler match only + if (index != control.exclusiveEventHandler) return; @@ -148,18 +151,20 @@ QWasmSuspendResumeControl::QWasmSuspendResumeControl() #endif qtSuspendResumeControlClearJs(); suspendResumeControlJs().set("asyncifyEnabled", qstdweb::haveAsyncify()); - QWasmSuspendResumeControl::s_suspendResumeControl = this; } QWasmSuspendResumeControl::~QWasmSuspendResumeControl() { + if (!m_eventHandlers.empty()) + qWarning() << "QWasmSuspendResumeControl::~QWasmSuspendResumeControl - still remaining " << m_eventHandlers.size() << " handlers"; qtSuspendResumeControlClearJs(); - QWasmSuspendResumeControl::s_suspendResumeControl = nullptr; } QWasmSuspendResumeControl *QWasmSuspendResumeControl::get() { - Q_ASSERT_X(s_suspendResumeControl, "QWasmSuspendResumeControl", "Must create a QWasmSuspendResumeControl instance first"); + if (!s_suspendResumeControl) + qFatal("QWasmSuspendResumeControl -- Object not created/destroyed"); + return s_suspendResumeControl; } @@ -244,8 +249,8 @@ int QWasmSuspendResumeControl::sendPendingEvents() void qtSendPendingEvents() { - if (QWasmSuspendResumeControl::s_suspendResumeControl) - QWasmSuspendResumeControl::s_suspendResumeControl->sendPendingEvents(); + if (s_suspendResumeControl) + s_suspendResumeControl->sendPendingEvents(); } EMSCRIPTEN_BINDINGS(qtSuspendResumeControl) { @@ -260,7 +265,6 @@ QWasmEventHandler::QWasmEventHandler(emscripten::val element, const std::string ,m_name(name) { QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); // must construct the event dispatcher or platform integration first m_eventHandlerIndex = suspendResume->registerEventHandler(std::move(handler)); m_element.call("addEventListener", m_name, suspendResume->jsEventHandlerAt(m_eventHandlerIndex)); } @@ -272,7 +276,6 @@ QWasmEventHandler::~QWasmEventHandler() return; QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); m_element.call("removeEventListener", m_name, suspendResume->jsEventHandlerAt(m_eventHandlerIndex)); suspendResume->removeEventHandler(m_eventHandlerIndex); } @@ -321,11 +324,13 @@ QWasmTimer::QWasmTimer(QWasmSuspendResumeControl *suspendResume, std::functionremoveEventHandler(m_handlerIndex); } void QWasmTimer::setTimeout(std::chrono::milliseconds timeout) { + Q_ASSERT(m_suspendResume == QWasmSuspendResumeControl::get()); if (hasTimeout()) clearTimeout(); val jsHandler = QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_handlerIndex); diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h index 4e75d5674b..483abb041c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #ifndef QWASMSUSPENDRESUMECONTROL_P_H #define QWASMSUSPENDRESUMECONTROL_P_H @@ -54,7 +55,6 @@ public: private: friend void qtSendPendingEvents(); - static QWasmSuspendResumeControl *s_suspendResumeControl; std::map> m_eventHandlers; std::function m_eventFilter = [](int) { return true; }; emscripten::val m_currentEvent = emscripten::val::undefined(); diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows.cpp b/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows.cpp index 801c9ab13d..24114979dc 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #include "quniquehandle_types_windows_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows_p.h b/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows_p.h index 638441a87e..63c8b7ff57 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/platform/windows/quniquehandle_types_windows_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2025 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 +// Qt-Security score:significant reason:default #ifndef QUNIQUEHANDLE_TYPES_WINDOWS_P_H #define QUNIQUEHANDLE_TYPES_WINDOWS_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qcoffpeparser_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qcoffpeparser_p.h index 4a28827a5e..249f3e2831 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qcoffpeparser_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qcoffpeparser_p.h @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // no, this is not a misspelling of "coffeeparser" +// Qt-Security score:significant reason:default #ifndef QCOFFPEPARSER_H #define QCOFFPEPARSER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp index cf28e3f65e..d5393cf17e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp @@ -1,7 +1,3 @@ -#ifndef ELFMAG -#define ELFMAG "ELF" -#endif - // Copyright (C) 2017 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only @@ -176,6 +172,9 @@ struct ElfHeaderCommonCheck // byte 6 static bool checkElfVersion(const uchar *ident) { +#ifdef Q_OS_REDOX + return true; +#endif uchar elfversion = ident[EI_VERSION]; return elfversion == EV_CURRENT; } @@ -257,6 +256,9 @@ struct ElfHeaderCheck : public ElfHeaderCommonCheck static bool checkFileVersion(const Ehdr &header) { +#ifdef Q_OS_REDOX + return true; +#endif return header.e_version == EV_CURRENT; } @@ -506,7 +508,7 @@ struct ErrorMaker Q_DECL_COLD_FUNCTION QLibraryScanResult operator()(QString &&text) const { - *errMsg = QLibrary::tr("'%1' is not a valid ELF object (%2)").arg(*errMsg, std::move(text)); + *errMsg = QLibrary::tr("'%1' is not a valid ELF object (%2)").arg(*errMsg, text); return {}; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp.orig b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp.orig new file mode 100644 index 0000000000..d251d647b4 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.cpp.orig @@ -0,0 +1,790 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:critical reason:data-parser + +#include "qelfparser_p.h" + +#ifdef Q_OF_ELF + +#include "qlibrary_p.h" + +#include +#include +#include + +#if __has_include() +# include +#elif __has_include() +# include +#else +# error "Need ELF header to parse plugins." +#endif + +QT_BEGIN_NAMESPACE + +using namespace Qt::StringLiterals; + +// ### Qt7: propagate the constant and eliminate dead code +static constexpr bool ElfNotesAreMandatory = QT_VERSION >= QT_VERSION_CHECK(7,0,0); + +// Whether we include some extra validity checks +// (checks to ensure we don't read out-of-bounds are always included) +static constexpr bool IncludeValidityChecks = true; + +#ifdef QT_BUILD_INTERNAL +# define QELFPARSER_DEBUG +#endif +#if defined(QELFPARSER_DEBUG) +Q_STATIC_LOGGING_CATEGORY(lcElfParser, "qt.core.plugin.elfparser") +# define qEDebug qCDebug(lcElfParser) << reinterpret_cast(error.errMsg->constData()) << ':' +#else +# define qEDebug if (false) {} else QNoDebug() +#endif + +#ifndef PT_GNU_EH_FRAME +# define PT_GNU_EH_FRAME 0x6474e550 +#endif +#ifndef PT_GNU_STACK +# define PT_GNU_STACK 0x6474e551 +#endif +#ifndef PT_GNU_RELRO +# define PT_GNU_RELRO 0x6474e552 +#endif +#ifndef PT_GNU_PROPERTY +# define PT_GNU_PROPERTY 0x6474e553 +#endif + +#ifndef PN_XNUM +# define PN_XNUM 0xffff +#endif + +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wunused-const-variable") + +namespace { +template struct ElfEndianTraits +{ + static constexpr unsigned char DataOrder = ELFDATA2LSB; + template static T fromEndian(T value) { return qFromLittleEndian(value); } +}; +template <> struct ElfEndianTraits +{ + static constexpr unsigned char DataOrder = ELFDATA2MSB; + template static T fromEndian(T value) { return qFromBigEndian(value); } +}; + +template struct ElfTypeTraits +{ + static constexpr unsigned char Class = ELFCLASS64; + + // integer types + using Half = Elf64_Half; + using Word = Elf64_Word; + using Addr = Elf64_Addr; + using Off = Elf64_Off; + + // structure types + using Ehdr = Elf64_Ehdr; + using Shdr = Elf64_Shdr; + using Phdr = Elf64_Phdr; + using Nhdr = Elf64_Nhdr; +}; +template <> struct ElfTypeTraits +{ + static constexpr unsigned char Class = ELFCLASS32; + + // integer types + using Half = Elf32_Half; + using Word = Elf32_Word; + using Addr = Elf32_Addr; + using Off = Elf32_Off; + + // structure types + using Ehdr = Elf32_Ehdr; + using Shdr = Elf32_Shdr; + using Phdr = Elf32_Phdr; + using Nhdr = Elf32_Nhdr; +}; + +struct ElfMachineCheck +{ + static const Elf32_Half ExpectedMachine = +#if 0 + // nothing +#elif defined(Q_PROCESSOR_ALPHA) + EM_ALPHA +#elif defined(Q_PROCESSOR_ARM_32) + EM_ARM +#elif defined(Q_PROCESSOR_ARM_64) + EM_AARCH64 +#elif defined(Q_PROCESSOR_BLACKFIN) + EM_BLACKFIN +#elif defined(Q_PROCESSOR_HPPA) + EM_PARISC +#elif defined(Q_PROCESSOR_IA64) + EM_IA_64 +#elif defined(Q_PROCESSOR_LOONGARCH) + EM_LOONGARCH +#elif defined(Q_PROCESSOR_M68K) + EM_68K +#elif defined(Q_PROCESSOR_MIPS) + EM_MIPS +#elif defined(Q_PROCESSOR_POWER_32) + EM_PPC +#elif defined(Q_PROCESSOR_POWER_64) + EM_PPC64 +#elif defined(Q_PROCESSOR_RISCV) + EM_RISCV +#elif defined(Q_PROCESSOR_S390) + EM_S390 +#elif defined(Q_PROCESSOR_SH) + EM_SH +#elif defined(Q_PROCESSOR_SPARC_V9) + EM_SPARCV9 +#elif defined(Q_PROCESSOR_SPARC_64) + EM_SPARCV9 +#elif defined(Q_PROCESSOR_SPARC) + EM_SPARC +#elif defined(Q_PROCESSOR_WASM) +#elif defined(Q_PROCESSOR_X86_32) + EM_386 +#elif defined(Q_PROCESSOR_X86_64) + EM_X86_64 +#else +# error "Unknown Q_PROCESSOR_xxx macro, please update." + EM_NONE +#endif + ; +}; + +struct ElfHeaderCommonCheck +{ + static_assert(std::is_same_v, + "e_ident field is not the same in both Elf32_Ehdr and Elf64_Ehdr"); + + // bytes 0-3 + static bool checkElfMagic(const uchar *ident) + { + return memcmp(ident, ELFMAG, SELFMAG) == 0; + } + + // byte 6 + static bool checkElfVersion(const uchar *ident) + { + uchar elfversion = ident[EI_VERSION]; + return elfversion == EV_CURRENT; + } + + struct CommonHeader { + Elf32_Half type; + Elf32_Half machine; + Elf32_Word version; + }; +}; + +template +struct ElfHeaderCheck : public ElfHeaderCommonCheck +{ + using TypeTraits = ElfTypeTraits; + using EndianTraits = ElfEndianTraits; + using Ehdr = typename TypeTraits::Ehdr; + + // byte 4 + static bool checkClass(const uchar *ident) + { + uchar klass = ident[EI_CLASS]; + return klass == TypeTraits::Class; + } + + // byte 5 + static bool checkDataOrder(const uchar *ident) + { + uchar data = ident[EI_DATA]; + return data == EndianTraits::DataOrder; + } + + // byte 7 + static bool checkOsAbi(const uchar *ident) + { + uchar osabi = ident[EI_OSABI]; + // we don't check + Q_UNUSED(osabi); + return true; + } + + // byte 8 + static bool checkAbiVersion(const uchar *ident) + { + uchar abiversion = ident[EI_ABIVERSION]; + // we don't check (and I don't know anyone who uses this) + Q_UNUSED(abiversion); + return true; + } + + // bytes 9-16 + static bool checkPadding(const uchar *ident) + { + // why would we check this? + Q_UNUSED(ident); + return true; + } + + static bool checkIdent(const Ehdr &header) + { + return checkElfMagic(header.e_ident) + && checkClass(header.e_ident) + && checkDataOrder(header.e_ident) + && checkElfVersion(header.e_ident) + && checkOsAbi(header.e_ident) + && checkAbiVersion(header.e_ident) + && checkPadding(header.e_ident); + } + + static bool checkType(const Ehdr &header) + { + return header.e_type == ET_DYN; + } + + static bool checkMachine(const Ehdr &header) + { + return header.e_machine == ElfMachineCheck::ExpectedMachine; + } + + static bool checkFileVersion(const Ehdr &header) + { + return header.e_version == EV_CURRENT; + } + + static bool checkHeader(const Ehdr &header) + { + if (!checkIdent(header)) + return false; + if (!IncludeValidityChecks) + return true; + return checkType(header) + && checkMachine(header) + && checkFileVersion(header); + } + + Q_DECL_COLD_FUNCTION static QString explainCheckFailure(const Ehdr &header) + { + if (!checkElfMagic(header.e_ident)) + return QLibrary::tr("invalid signature"); + if (!checkClass(header.e_ident)) + return QLibrary::tr("file is for a different word size"); + if (!checkDataOrder(header.e_ident)) + return QLibrary::tr("file is for the wrong endianness"); + if (!checkElfVersion(header.e_ident) || !checkFileVersion(header)) + return QLibrary::tr("file has an unknown ELF version"); + if (!checkOsAbi(header.e_ident) || !checkAbiVersion(header.e_ident)) + return QLibrary::tr("file has an unexpected ABI"); + if (!checkType(header)) + return QLibrary::tr("file is not a shared object"); + if (!checkMachine(header)) + return QLibrary::tr("file is for a different processor"); + return QString(); + } + + static CommonHeader extractCommonHeader(const uchar *data) + { + auto header = reinterpret_cast(data); + CommonHeader r; + r.type = EndianTraits::fromEndian(header->e_type); + r.machine = EndianTraits::fromEndian(header->e_machine); + r.version = EndianTraits::fromEndian(header->e_version); + return r; + } +}; + +struct ElfHeaderDebug { const uchar *e_ident; }; +Q_DECL_UNUSED Q_DECL_COLD_FUNCTION static QDebug &operator<<(QDebug &d, ElfHeaderDebug h) +{ + const uchar *e_ident = h.e_ident; + if (!ElfHeaderCommonCheck::checkElfMagic(e_ident)) { + d << "Not an ELF file (invalid signature)"; + return d; + } + + QDebugStateSaver saver(d); + d.nospace(); + quint8 elfclass = e_ident[EI_CLASS]; + switch (elfclass) { + case ELFCLASSNONE: + default: + d << "Invalid ELF file (class " << e_ident[EI_CLASS] << "), "; + break; + case ELFCLASS32: + d << "ELF 32-bit "; + break; + case ELFCLASS64: + d << "ELF 64-bit "; + break; + } + + quint8 dataorder = e_ident[EI_DATA]; + switch (dataorder) { + case ELFDATANONE: + default: + d << "invalid endianness (" << e_ident[EI_DATA] << ')'; + break; + case ELFDATA2LSB: + d << "LSB"; + break; + case ELFDATA2MSB: + d << "MSB"; + break; + } + + switch (e_ident[EI_OSABI]) { + case ELFOSABI_SYSV: d << " (SYSV"; break; + case ELFOSABI_HPUX: d << " (HP-UX"; break; + case ELFOSABI_NETBSD: d << " (NetBSD"; break; + case ELFOSABI_LINUX: d << " (GNU/Linux"; break; + case ELFOSABI_SOLARIS: d << " (Solaris"; break; + case ELFOSABI_AIX: d << " (AIX"; break; + case ELFOSABI_IRIX: d << " (IRIX"; break; + case ELFOSABI_FREEBSD: d << " (FreeBSD"; break; + case ELFOSABI_OPENBSD: d << " (OpenBSD"; break; + default: d << " (OS ABI " << e_ident[EI_VERSION]; break; + } + + if (e_ident[EI_ABIVERSION]) + d << " v" << e_ident[EI_ABIVERSION]; + d << ')'; + + if (e_ident[EI_VERSION] != 1) { + d << ", file version " << e_ident[EI_VERSION]; + return d; + } + + ElfHeaderCommonCheck::CommonHeader r; + if (elfclass == ELFCLASS64 && dataorder == ELFDATA2LSB) + r = ElfHeaderCheck::extractCommonHeader(e_ident); + else if (elfclass == ELFCLASS32 && dataorder == ELFDATA2LSB) + r = ElfHeaderCheck::extractCommonHeader(e_ident); + else if (elfclass == ELFCLASS64 && dataorder == ELFDATA2MSB) + r = ElfHeaderCheck::extractCommonHeader(e_ident); + else if (elfclass == ELFCLASS32 && dataorder == ELFDATA2MSB) + r = ElfHeaderCheck::extractCommonHeader(e_ident); + else + return d; + + d << ", version " << r.version; + + switch (r.type) { + case ET_NONE: d << ", no type"; break; + case ET_REL: d << ", relocatable"; break; + case ET_EXEC: d << ", executable"; break; + case ET_DYN: d << ", shared library or PIC executable"; break; + case ET_CORE: d << ", core dump"; break; + default: d << ", unknown type " << r.type; break; + } + + switch (r.machine) { + // list definitely not exhaustive! + case EM_NONE: d << ", no machine"; break; + case EM_ALPHA: d << ", Alpha"; break; + case EM_68K: d << ", MC68000"; break; + case EM_ARM: d << ", ARM"; break; + case EM_AARCH64: d << ", AArch64"; break; +#ifdef EM_BLACKFIN + case EM_BLACKFIN: d << ", Blackfin"; break; +#endif + case EM_IA_64: d << ", IA-64"; break; +#ifdef EM_LOONGARCH + case EM_LOONGARCH: d << ", LoongArch"; break; +#endif + case EM_MIPS: d << ", MIPS"; break; + case EM_PARISC: d << ", HPPA"; break; + case EM_PPC: d << ", PowerPC"; break; + case EM_PPC64: d << ", PowerPC 64-bit"; break; +#ifdef EM_RISCV + case EM_RISCV: d << ", RISC-V"; break; +#endif +#ifdef EM_S390 + case EM_S390: d << ", S/390"; break; +#endif + case EM_SH: d << ", SuperH"; break; + case EM_SPARC: d << ", SPARC"; break; + case EM_SPARCV9: d << ", SPARCv9"; break; + case EM_386: d << ", i386"; break; + case EM_X86_64: d << ", x86-64"; break; + default: d << ", other machine type " << r.machine; break; + } + + return d; +} + +struct ElfSectionDebug { const ElfHeaderCheck<>::TypeTraits::Shdr *shdr; }; +Q_DECL_UNUSED static QDebug &operator<<(QDebug &d, ElfSectionDebug s) +{ + // not exhaustive, just a few common things + QDebugStateSaver saver(d); + d << Qt::hex << Qt::showbase; + d << "type"; + switch (s.shdr->sh_type) { + case SHT_NULL: d << "NULL"; break; + case SHT_PROGBITS: d << "PROGBITS"; break; + case SHT_SYMTAB: d << "SYMTAB"; break; + case SHT_STRTAB: d << "STRTAB"; break; + case SHT_RELA: d << "RELA"; break; + case SHT_HASH: d << "HASH"; break; + case SHT_DYNAMIC: d << "DYNAMIC"; break; + case SHT_NOTE: d << "NOTE"; break; + case SHT_NOBITS: d << "NOBITS"; break; + case SHT_DYNSYM: d << "DYNSYM"; break; + case SHT_INIT_ARRAY: d << "INIT_ARRAY"; break; + case SHT_FINI_ARRAY: d << "FINI_ARRAY"; break; + default: d << s.shdr->sh_type; + } + + d << "flags"; + d.nospace(); + if (s.shdr->sh_flags & SHF_WRITE) + d << 'W'; + if (s.shdr->sh_flags & SHF_ALLOC) + d << 'A'; + if (s.shdr->sh_flags & SHF_EXECINSTR) + d << 'X'; + if (s.shdr->sh_flags & SHF_STRINGS) + d << 'S'; + if (s.shdr->sh_flags & SHF_TLS) + d << 'T'; + + d.space() << "offset" << s.shdr->sh_offset << "size" << s.shdr->sh_size; + return d; +} + +struct ElfProgramDebug { const ElfHeaderCheck<>::TypeTraits::Phdr *phdr; }; +Q_DECL_UNUSED static QDebug &operator<<(QDebug &d, ElfProgramDebug p) +{ + QDebugStateSaver saved(d); + d << Qt::hex << Qt::showbase << "program"; + switch (p.phdr->p_type) { + case PT_NULL: d << "NULL"; break; + case PT_LOAD: d << "LOAD"; break; + case PT_DYNAMIC: d << "DYNAMIC"; break; + case PT_INTERP: d << "INTERP"; break; + case PT_NOTE: d << "NOTE"; break; + case PT_PHDR: d << "PHDR"; break; + case PT_TLS: d << "TLS"; break; + case PT_GNU_EH_FRAME: d << "GNU_EH_FRAME"; break; + case PT_GNU_STACK: d << "GNU_STACK"; break; + case PT_GNU_RELRO: d << "GNU_RELRO"; break; + case PT_GNU_PROPERTY: d << "GNU_PROPERTY"; break; + default: d << "type" << p.phdr->p_type; break; + } + + d << "offset" << p.phdr->p_offset + << "virtaddr" << p.phdr->p_vaddr + << "filesz" << p.phdr->p_filesz + << "memsz" << p.phdr->p_memsz + << "align" << p.phdr->p_align + << "flags"; + + d.nospace(); + if (p.phdr->p_flags & PF_R) + d << 'R'; + if (p.phdr->p_flags & PF_W) + d << 'W'; + if (p.phdr->p_flags & PF_X) + d << 'X'; + + return d; +} + +struct ErrorMaker +{ + QString *errMsg; + constexpr ErrorMaker(QString *errMsg) : errMsg(errMsg) {} + + + Q_DECL_COLD_FUNCTION QLibraryScanResult operator()(QString &&text) const + { + *errMsg = QLibrary::tr("'%1' is not a valid ELF object (%2)").arg(*errMsg, text); + return {}; + } + + Q_DECL_COLD_FUNCTION QLibraryScanResult notplugin(QString &&explanation) const + { + *errMsg = QLibrary::tr("'%1' is not a Qt plugin (%2)").arg(*errMsg, explanation); + return {}; + } + + Q_DECL_COLD_FUNCTION QLibraryScanResult notfound() const + { + return notplugin(QLibrary::tr("metadata not found")); + } +}; +} // unnamed namespace + +QT_WARNING_POP + +using T = ElfHeaderCheck<>::TypeTraits; + +template +static bool scanProgramHeaders(QByteArrayView data, const ErrorMaker &error, F f) +{ + auto header = reinterpret_cast(data.data()); + Q_UNUSED(error); + + auto phdr = reinterpret_cast(data.data() + header->e_phoff); + auto phdr_end = phdr + header->e_phnum; + for ( ; phdr != phdr_end; ++phdr) { + if (!f(phdr)) + return false; + } + return true; +} + +static bool preScanProgramHeaders(QByteArrayView data, const ErrorMaker &error) +{ + auto header = reinterpret_cast(data.data()); + + // first, validate the extent of the full program header table + T::Word e_phnum = header->e_phnum; + if (e_phnum == PN_XNUM) + return error(QLibrary::tr("unimplemented: PN_XNUM program headers")), false; + T::Off offset = e_phnum * sizeof(T::Phdr); // can't overflow due to size of T::Half + if (qAddOverflow(offset, header->e_phoff, &offset) || offset > size_t(data.size())) + return error(QLibrary::tr("program header table extends past the end of the file")), false; + + // confirm validity + bool hasCode = false; + auto checker = [&](const T::Phdr *phdr) { + qEDebug << ElfProgramDebug{phdr}; + + if (T::Off end; qAddOverflow(phdr->p_offset, phdr->p_filesz, &end) + || end > size_t(data.size())) + return error(QLibrary::tr("a program header entry extends past the end of the file")), false; + + // this is not a validity check, it's to exclude debug symbol files + if (phdr->p_type == PT_LOAD && phdr->p_filesz != 0 && (phdr->p_flags & PF_X)) + hasCode = true; + + // this probably applies to all segments, but we'll only apply it to notes + if (phdr->p_type == PT_NOTE && qPopulationCount(phdr->p_align) == 1 + && phdr->p_offset & (phdr->p_align - 1)) { + return error(QLibrary::tr("a note segment start is not properly aligned " + "(offset 0x%1, alignment %2)") + .arg(phdr->p_offset, 6, 16, QChar(u'0')) + .arg(phdr->p_align)), false; + } + + return true; + }; + if (!scanProgramHeaders(data, error, checker)) + return false; + if (!hasCode) + return error.notplugin(QLibrary::tr("file has no code")), false; + return true; +} + +static QLibraryScanResult scanProgramHeadersForNotes(QByteArrayView data, const ErrorMaker &error) +{ + // minimum metadata payload is 2 bytes + constexpr size_t MinPayloadSize = sizeof(QPluginMetaData::Header) + 2; + constexpr qptrdiff MinNoteSize = sizeof(QPluginMetaData::ElfNoteHeader) + 2; + constexpr size_t NoteNameSize = sizeof(QPluginMetaData::ElfNoteHeader::name); + constexpr size_t NoteAlignment = alignof(QPluginMetaData::ElfNoteHeader); + constexpr qptrdiff PayloadStartDelta = offsetof(QPluginMetaData::ElfNoteHeader, header); + static_assert(MinNoteSize > PayloadStartDelta); + static_assert((PayloadStartDelta & (NoteAlignment - 1)) == 0); + + QLibraryScanResult r = {}; + auto noteFinder = [&](const T::Phdr *phdr) { + if (phdr->p_type != PT_NOTE || phdr->p_align != NoteAlignment) + return true; + + // check for signed integer overflows, to avoid issues with the + // arithmetic below + if (qptrdiff(phdr->p_filesz) < 0) { + auto h = reinterpret_cast(data.data()); + auto segments = reinterpret_cast(data.data() + h->e_phoff); + qEDebug << "segment" << (phdr - segments) << "contains a note with size" + << Qt::hex << Qt::showbase << phdr->p_filesz + << "which is larger than half the virtual memory space"; + return true; + } + + // iterate over the notes in this segment + T::Off offset = phdr->p_offset; + const T::Off end_offset = offset + phdr->p_filesz; + while (qptrdiff(end_offset - offset) >= MinNoteSize) { + auto nhdr = reinterpret_cast(data.data() + offset); + T::Word n_namesz = nhdr->n_namesz; + T::Word n_descsz = nhdr->n_descsz; + T::Word n_type = nhdr->n_type; + + // overflow check: calculate where the next note will be, if it exists + T::Off next_offset = offset; + next_offset += sizeof(T::Nhdr); // can't overflow (we checked above) + next_offset += NoteAlignment - 3; // offset is aligned, this can't overflow + if (qAddOverflow(next_offset, n_namesz, &next_offset)) + break; + next_offset &= -NoteAlignment; + + next_offset += NoteAlignment - 3; // offset is aligned, this can't overflow + if (qAddOverflow(next_offset, n_descsz, &next_offset)) + break; + next_offset &= -NoteAlignment; + if (next_offset > end_offset) + break; + + if (n_namesz == NoteNameSize && n_descsz >= MinPayloadSize + && n_type == QPluginMetaData::ElfNoteHeader::NoteType + && memcmp(nhdr + 1, QPluginMetaData::ElfNoteHeader::NoteName, NoteNameSize) == 0) { + // yes, it's our note + r.pos = offset + PayloadStartDelta; + r.length = nhdr->n_descsz; + return false; + } + offset = next_offset; + } + return true; + }; + scanProgramHeaders(data, error, noteFinder); + + if (!r.length) + return r; + + qEDebug << "found Qt metadata in ELF note at" + << Qt::hex << Qt::showbase << r.pos << "size" << Qt::reset << r.length; + return r; +} + +static QLibraryScanResult scanSections(QByteArrayView data, const ErrorMaker &error) +{ + auto header = reinterpret_cast(data.data()); + + // in order to find the .qtmetadata section, we need to: + // a) find the section table + // it's located at offset header->e_shoff + // validate it + T::Word e_shnum = header->e_shnum; + T::Off offset = e_shnum * sizeof(T::Shdr); // can't overflow due to size of T::Half + if (qAddOverflow(offset, header->e_shoff, &offset) || offset > size_t(data.size())) + return error(QLibrary::tr("section table extends past the end of the file")); + + // b) find the section entry for the section header string table (shstrab) + // it's a section whose entry is pointed by e_shstrndx + auto sections = reinterpret_cast(data.data() + header->e_shoff); + auto sections_end = sections + e_shnum; + auto shdr = sections + header->e_shstrndx; + + // validate the shstrtab + offset = shdr->sh_offset; + T::Off shstrtab_size = shdr->sh_size; + qEDebug << "shstrtab section is located at offset" << offset << "size" << shstrtab_size; + if (T::Off end; qAddOverflow(offset, shstrtab_size, &end) + || end > size_t(data.size())) + return error(QLibrary::tr("section header string table extends past the end of the file")); + + // c) iterate over the sections to find .qtmetadata + const char *shstrtab_start = data.data() + offset; + shdr = sections; + for (int section = 0; shdr != sections_end; ++section, ++shdr) { + QLatin1StringView name; + if (shdr->sh_name < shstrtab_size) { + const char *namestart = shstrtab_start + shdr->sh_name; + size_t len = qstrnlen(namestart, shstrtab_size - shdr->sh_name); + name = QLatin1StringView(namestart, len); + } + qEDebug << "section" << section << "name" << name << ElfSectionDebug{shdr}; + + // sanity check the section + if (name.isNull()) + return error(QLibrary::tr("a section name extends past the end of the file")); + + // sections aren't allowed to extend past the end of the file, unless + // they are NOBITS sections + if (shdr->sh_type == SHT_NOBITS) + continue; + if (T::Off end; qAddOverflow(shdr->sh_offset, shdr->sh_size, &end) + || end > size_t(data.size())) { + return error(QLibrary::tr("section contents extend past the end of the file")); + } + + if (name != ".qtmetadata"_L1) + continue; + qEDebug << "found .qtmetadata section"; + if (shdr->sh_size < sizeof(QPluginMetaData::MagicHeader)) + return error(QLibrary::tr(".qtmetadata section is too small")); + + if (IncludeValidityChecks) { + QByteArrayView expectedMagic = QByteArrayView::fromArray(QPluginMetaData::MagicString); + QByteArrayView actualMagic = data.sliced(shdr->sh_offset, expectedMagic.size()); + if (expectedMagic != actualMagic) + return error(QLibrary::tr(".qtmetadata section has incorrect magic")); + + if (shdr->sh_flags & SHF_WRITE) + return error(QLibrary::tr(".qtmetadata section is writable")); + if (shdr->sh_flags & SHF_EXECINSTR) + return error(QLibrary::tr(".qtmetadata section is executable")); + } + + return { qsizetype(shdr->sh_offset + sizeof(QPluginMetaData::MagicString)), + qsizetype(shdr->sh_size - sizeof(QPluginMetaData::MagicString)) }; + } + + // section .qtmetadata not found + return error.notfound(); +} + +QLibraryScanResult QElfParser::parse(QByteArrayView data, QString *errMsg) +{ + ErrorMaker error(errMsg); + if (size_t(data.size()) < sizeof(T::Ehdr)) { + qEDebug << "file too small:" << size_t(data.size()); + return error(QLibrary::tr("file too small")); + } + + qEDebug << ElfHeaderDebug{ reinterpret_cast(data.data()) }; + + auto header = reinterpret_cast(data.data()); + if (!ElfHeaderCheck<>::checkHeader(*header)) + return error(ElfHeaderCheck<>::explainCheckFailure(*header)); + + qEDebug << "contains" << header->e_phnum << "program headers of" + << header->e_phentsize << "bytes at offset" << header->e_phoff; + qEDebug << "contains" << header->e_shnum << "sections of" << header->e_shentsize + << "bytes at offset" << header->e_shoff + << "; section header string table (shstrtab) is entry" << header->e_shstrndx; + + // some sanity checks + if constexpr (IncludeValidityChecks) { + if (header->e_phentsize != sizeof(T::Phdr)) + return error(QLibrary::tr("unexpected program header entry size (%1)") + .arg(header->e_phentsize)); + } + + if (!preScanProgramHeaders(data, error)) + return {}; + + if (QLibraryScanResult r = scanProgramHeadersForNotes(data, error); r.length) + return r; + + if (!ElfNotesAreMandatory) { + if constexpr (IncludeValidityChecks) { + if (header->e_shentsize != sizeof(T::Shdr)) + return error(QLibrary::tr("unexpected section entry size (%1)") + .arg(header->e_shentsize)); + } + if (header->e_shoff == 0 || header->e_shnum == 0) { + // this is still a valid ELF file but we don't have a section table + qEDebug << "no section table present, not able to find Qt metadata"; + return error.notfound(); + } + + if (header->e_shnum && header->e_shstrndx >= header->e_shnum) + return error(QLibrary::tr("e_shstrndx greater than the number of sections e_shnum (%1 >= %2)") + .arg(header->e_shstrndx).arg(header->e_shnum)); + return scanSections(data, error); + } + return error.notfound(); +} + +QT_END_NAMESPACE + +#endif // Q_OF_ELF diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.h index 61498a859a..23ff3f18d6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qelfparser_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QELFPARSER_P_H #define QELFPARSER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.cpp b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.cpp index 1a48d311aa..db477d8925 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qfactoryinterface.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.h index 098b7d4201..aed3942a4f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryinterface.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QFACTORYINTERFACE_H #define QFACTORYINTERFACE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryloader_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryloader_p.h index d7482b3619..a81d20be58 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryloader_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qfactoryloader_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2017 The Qt Company Ltd. // Copyright (C) 2022 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QFACTORYLOADER_P_H #define QFACTORYLOADER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.cpp b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.cpp index 957b42ebfc..498ca56061 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.cpp @@ -680,7 +680,7 @@ bool QLibrary::isLibrary(const QString &fileName) static bool qt_get_metadata(QLibraryPrivate *priv, QString *errMsg) { auto error = [=](QString &&explanation) { - *errMsg = QLibrary::tr("'%1' is not a Qt plugin (%2)").arg(priv->fileName, std::move(explanation)); + *errMsg = QLibrary::tr("'%1' is not a Qt plugin (%2)").arg(priv->fileName, explanation); return false; }; diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.h index 95c14178b2..812a481512 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QLIBRARY_H #define QLIBRARY_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary_p.h index 2331c86d84..28412d161f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qlibrary_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QLIBRARY_P_H #define QLIBRARY_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qmachparser_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qmachparser_p.h index 85a174e66e..4f3cfd99fb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qmachparser_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qmachparser_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QMACHPARSER_P_H #define QMACHPARSER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h index b7322ac1c3..0268c51c04 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPLUGIN_H #define QPLUGIN_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h.orig b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h.orig new file mode 100644 index 0000000000..fe1d81f7b2 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin.h.orig @@ -0,0 +1,271 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default + +#ifndef QPLUGIN_H +#define QPLUGIN_H + +#if 0 +#pragma qt_class(QtPlugin) +#endif + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +// Used up to Qt 6.2 +inline constexpr unsigned char qPluginArchRequirements() +{ + return 0 +#ifndef QT_NO_DEBUG + | 1 +#endif +#ifdef __AVX2__ + | 2 +# ifdef __AVX512F__ + | 4 +# endif +#endif + ; +} + +typedef QObject *(*QtPluginInstanceFunction)(); +struct QPluginMetaData +{ + static constexpr quint8 CurrentMetaDataVersion = 1; + static constexpr char MagicString[] = { + 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!' + }; + + template + static constexpr void copy(OO (&out)[OSize], II (&in)[ISize]) + { + static_assert(OSize <= ISize, "Output would not be fully initialized"); + q20::copy_n(in, OSize, out); + } + + static constexpr quint8 archRequirements() + { + quint8 v = 0; +#if defined(__AVX512F__) + v = 4; // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ and AVX512VL +#elif defined(__AVX__) || defined(__BMI__) || defined(__BMI2__) || defined(__MOVBE__) + v = 3; // x86-64-v3: AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE +#elif defined(__SSE3__) + v = 2; // x86-64-v2: POPCNT, SSE3, SSSE3, SSE4.1 and SSE4.2. +#elif defined(__SSE__) || defined(__MMX___) + v = 1; // x86-64 baseline: SSE and SSE2 +#endif +#ifndef QT_NO_DEBUG + v |= 0x80; +#endif + return v; + } + + struct Header { + quint8 version = CurrentMetaDataVersion; + quint8 qt_major_version = QT_VERSION_MAJOR; + quint8 qt_minor_version = QT_VERSION_MINOR; + quint8 plugin_arch_requirements = archRequirements(); + }; + static_assert(alignof(Header) == 1, "Alignment of header incorrect with this compiler"); + + struct MagicHeader { + char magic[sizeof(QPluginMetaData::MagicString)] = {}; + constexpr MagicHeader() { copy(magic, QPluginMetaData::MagicString); } + Header header = {}; + }; + static_assert(alignof(MagicHeader) == 1, "Alignment of header incorrect with this compiler"); + + struct ElfNoteHeader { + static constexpr quint32 NoteType = 0x74510001; + static constexpr char NoteName[] = "qt-project!"; + + // ELF note header + quint32 n_namesz = sizeof(name); + quint32 n_descsz; + quint32 n_type = NoteType; + char name[sizeof(NoteName)] = {}; + + // payload + alignas(void *) // mandatory alignment as per ELF note requirements + Header header = {}; + constexpr ElfNoteHeader(quint32 payloadSize) : n_descsz(sizeof(header) + payloadSize) + { QPluginMetaData::copy(name, NoteName); } + }; + static_assert(alignof(ElfNoteHeader) == alignof(void*), "Alignment of header incorrect with this compiler"); + static_assert((sizeof(ElfNoteHeader::name) % 4) == 0, "ELF note name length not a multiple of 4"); + + const void *data; + size_t size; +}; +typedef QPluginMetaData (*QtPluginMetaDataFunction)(); + + +struct Q_CORE_EXPORT QStaticPlugin +{ +public: + constexpr QStaticPlugin(QtPluginInstanceFunction i, QtPluginMetaDataFunction m) + : instance(i), rawMetaDataSize(m().size), rawMetaData(m().data) + {} + QtPluginInstanceFunction instance; + QJsonObject metaData() const; + +private: + qsizetype rawMetaDataSize; + const void *rawMetaData; + friend class QFactoryLoader; +}; +Q_DECLARE_TYPEINFO(QStaticPlugin, Q_PRIMITIVE_TYPE); + +void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); + +#if defined(Q_OF_ELF) || (defined(Q_OS_WIN) && (defined (Q_CC_GNU) || defined(Q_CC_CLANG))) +# define QT_PLUGIN_METADATA_SECTION \ + __attribute__ ((section (".qtmetadata"))) __attribute__((used)) +#elif defined(Q_OS_DARWIN) +# define QT_PLUGIN_METADATA_SECTION \ + __attribute__ ((section ("__TEXT,qtmetadata"))) __attribute__((used)) +#elif defined(Q_CC_MSVC) +// TODO: Implement section parsing for MSVC +#pragma section(".qtmetadata",read,shared) +# define QT_PLUGIN_METADATA_SECTION \ + __declspec(allocate(".qtmetadata")) +#else +# define QT_PLUGIN_METADATA_SECTION +#endif + +// Since Qt 6.3 +template class QPluginMetaDataV2 +{ + struct ElfNotePayload : QPluginMetaData::ElfNoteHeader { + static constexpr size_t HeaderOffset = offsetof(QPluginMetaData::ElfNoteHeader, header); + quint8 payload[sizeof(PluginMetaData)] = {}; + constexpr ElfNotePayload() : ElfNoteHeader(sizeof(PluginMetaData)) + { QPluginMetaData::copy(payload, PluginMetaData); } + }; + + struct RegularPayload : QPluginMetaData::MagicHeader { + static constexpr size_t HeaderOffset = offsetof(QPluginMetaData::MagicHeader, header); + quint8 payload[sizeof(PluginMetaData)] = {}; + constexpr RegularPayload() { QPluginMetaData::copy(payload, PluginMetaData); } + }; + + struct StaticPayload { + static constexpr size_t HeaderOffset = 0; + QPluginMetaData::Header header = {}; + quint8 payload[sizeof(PluginMetaData)] = {}; + constexpr StaticPayload() { QPluginMetaData::copy(payload, PluginMetaData); } + }; + +#if defined(QT_STATICPLUGIN) +# define QT_PLUGIN_METADATAV2_SECTION + using Payload = StaticPayload; +#elif defined(Q_OF_ELF) +# ifdef Q_CC_CLANG +# define QT_PLUGIN_METADATAV2_SECTION \ + __attribute__((section(".note.qt.metadata"), used, aligned(alignof(void *)), \ + no_sanitize("address"))) +# else +# define QT_PLUGIN_METADATAV2_SECTION \ + __attribute__((section(".note.qt.metadata"), used, aligned(alignof(void *)))) +# endif + using Payload = ElfNotePayload; +#else +# define QT_PLUGIN_METADATAV2_SECTION QT_PLUGIN_METADATA_SECTION + using Payload = RegularPayload; +#endif + + Payload payload = {}; + +public: + operator QPluginMetaData() const + { + Q_ASSERT(reinterpret_cast(&payload) + Payload::HeaderOffset == + reinterpret_cast(&payload.header)); + return { &payload.header, sizeof(payload) - Payload::HeaderOffset }; + } +}; + +#define Q_IMPORT_PLUGIN(PLUGIN) \ + extern const QT_PREPEND_NAMESPACE(QStaticPlugin) QT_MANGLE_NAMESPACE(qt_static_plugin_##PLUGIN)(); \ + namespace { \ + struct Static##PLUGIN##PluginInstance { \ + Static##PLUGIN##PluginInstance() { \ + qRegisterStaticPluginFunction(QT_MANGLE_NAMESPACE(qt_static_plugin_##PLUGIN)()); \ + } \ + }; \ + } /* namespace */ \ + /* QTBUG-139615: static, to work around bug in clazy-non-pod-global-static */ \ + static Static##PLUGIN##PluginInstance static##PLUGIN##Instance; \ + +#if defined(QT_PLUGIN_RESOURCE_INIT_FUNCTION) +# define QT_PLUGIN_RESOURCE_INIT \ + extern void QT_PLUGIN_RESOURCE_INIT_FUNCTION(); \ + QT_PLUGIN_RESOURCE_INIT_FUNCTION(); +#else +# define QT_PLUGIN_RESOURCE_INIT +#endif + +#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \ + { \ + static QT_PREPEND_NAMESPACE(QPointer) _instance; \ + if (!_instance) { \ + QT_PLUGIN_RESOURCE_INIT \ + _instance = new IMPLEMENTATION; \ + } \ + return _instance; \ + } + +#if defined(QT_STATICPLUGIN) +# define QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) \ + static QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##MANGLEDNAME() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) \ + const QT_PREPEND_NAMESPACE(QStaticPlugin) QT_MANGLE_NAMESPACE(qt_static_plugin_##MANGLEDNAME)() \ + { return { qt_plugin_instance_##MANGLEDNAME, qt_plugin_query_metadata_##MANGLEDNAME}; } \ + /**/ + +# define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \ + static QPluginMetaData qt_plugin_query_metadata_##PLUGINCLASSNAME() \ + { return { qt_pluginMetaData_##PLUGINCLASSNAME, sizeof qt_pluginMetaData_##PLUGINCLASSNAME }; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, PLUGINCLASSNAME) + +# define QT_MOC_EXPORT_PLUGIN_V2(PLUGINCLASS, MANGLEDNAME, MD) \ + static QT_PREPEND_NAMESPACE(QPluginMetaData) qt_plugin_query_metadata_##MANGLEDNAME() \ + { static constexpr QPluginMetaDataV2 md{}; return md; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) +#else +# define QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) \ + extern "C" Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) \ + /**/ + +# define QT_MOC_EXPORT_PLUGIN(PLUGINCLASS, PLUGINCLASSNAME) \ + extern "C" Q_DECL_EXPORT \ + QPluginMetaData qt_plugin_query_metadata() \ + { return { qt_pluginMetaData_##PLUGINCLASSNAME, sizeof qt_pluginMetaData_##PLUGINCLASSNAME }; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, PLUGINCLASSNAME) + +# define QT_MOC_EXPORT_PLUGIN_V2(PLUGINCLASS, MANGLEDNAME, MD) \ + extern "C" Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QPluginMetaData) qt_plugin_query_metadata_v2()\ + { static constexpr QT_PLUGIN_METADATAV2_SECTION QPluginMetaDataV2 md{}; return md; } \ + QT_MOC_EXPORT_PLUGIN_COMMON(PLUGINCLASS, MANGLEDNAME) +#endif + +#define Q_EXPORT_PLUGIN(PLUGIN) \ + Q_EXPORT_PLUGIN2(PLUGIN, PLUGIN) +# define Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS) \ + static_assert(false, "Old plugin system used") + +# define Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS) \ + static_assert(false, "Old plugin system used") + + +QT_END_NAMESPACE + +#endif // Q_PLUGIN_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin_p.h index 1651fd3a95..8e6e762ea5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qplugin_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2018 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QPLUGIN_P_H #define QPLUGIN_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qpluginloader.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qpluginloader.h index e541994e62..97ae83f58b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qpluginloader.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qpluginloader.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QPLUGINLOADER_H #define QPLUGINLOADER_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary.cpp b/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary.cpp index ed11080a38..a40a1224de 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #include "qsystemlibrary_p.h" #include diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary_p.h index 0b4ad7dbc2..2ad13e81d6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/qsystemlibrary_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2016 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 +// Qt-Security score:significant reason:default #ifndef QSYSTEMLIBRARY_P_H #define QSYSTEMLIBRARY_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid.h index e19a4b7c52..481abaf724 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QUUID_H #define QUUID_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid_p.h b/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid_p.h index 871fc57195..26c79d14a3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/plugin/quuid_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QUUID_P_H #define QUUID_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/serialization/qcborvalue.h b/local/recipes/qt/qtbase/source/src/corelib/serialization/qcborvalue.h index 4dba5370ad..3c027f9595 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/serialization/qcborvalue.h +++ b/local/recipes/qt/qtbase/source/src/corelib/serialization/qcborvalue.h @@ -302,6 +302,8 @@ private: }; Q_DECLARE_SHARED(QCborValue) +Q_CORE_EXPORT size_t qHash(const QCborValue &value, size_t seed = 0); + class QCborValueConstRef { public: @@ -402,6 +404,10 @@ protected: friend class QCborContainerPrivate; QCborValue concrete() const noexcept { return concrete(*this); } + + friend size_t qHash(const QCborValueConstRef &key, size_t seed = 0) noexcept + { return QHashPrivate::ex1to2arg(key.concrete(), seed); } + static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept; static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering @@ -611,8 +617,6 @@ QT_WARNING_POP Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::EncodingOptions) Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::DiagnosticNotationOptions) -Q_CORE_EXPORT size_t qHash(const QCborValue &value, size_t seed = 0); - #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborValue &v); #endif diff --git a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.cpp b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.cpp index 8ee43f7f05..a79bf2a059 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.cpp @@ -71,27 +71,25 @@ QJsonDocument::QJsonDocument() * Creates a QJsonDocument from \a object. */ QJsonDocument::QJsonDocument(const QJsonObject &object) - : d(nullptr) + : QJsonDocument(QCborMap::fromJsonObject(object)) { - setObject(object); } /*! * Constructs a QJsonDocument from \a array. */ QJsonDocument::QJsonDocument(const QJsonArray &array) - : d(nullptr) + : QJsonDocument(QCborArray::fromJsonArray(array)) { - setArray(array); } /*! \internal + Only called from this .cpp file. */ -QJsonDocument::QJsonDocument(const QCborValue &data) - : d(std::make_unique(data)) +QJsonDocument::QJsonDocument(QCborValue data) + : d(new QJsonDocumentPrivate(std::move(data))) { - Q_ASSERT(d); } /*! @@ -105,14 +103,8 @@ QJsonDocument::~QJsonDocument() = default; * Creates a copy of the \a other document. */ QJsonDocument::QJsonDocument(const QJsonDocument &other) + : d(other.d ? std::make_unique(other.d->value) : nullptr) { - if (other.d) { - if (!d) - d = std::make_unique(); - d->value = other.d->value; - } else { - d.reset(); - } } QJsonDocument::QJsonDocument(QJsonDocument &&other) noexcept @@ -176,19 +168,18 @@ QJsonDocument QJsonDocument::fromVariant(const QVariant &variant) { QJsonDocument doc; - switch (variant.metaType().id()) { + switch (variant.userType()) { case QMetaType::QVariantMap: - doc.setObject(QJsonObject::fromVariantMap(variant.toMap())); + doc.setObject(QJsonObject::fromVariantMap(get(variant))); break; case QMetaType::QVariantHash: - doc.setObject(QJsonObject::fromVariantHash(variant.toHash())); + doc.setObject(QJsonObject::fromVariantHash(get(variant))); break; case QMetaType::QVariantList: - doc.setArray(QJsonArray::fromVariantList(variant.toList())); + doc.setArray(QJsonArray::fromVariantList(get(variant))); break; case QMetaType::QStringList: - doc.d = std::make_unique(); - doc.d->value = QCborArray::fromStringList(variant.toStringList()); + doc = QJsonDocument(QCborArray::fromStringList(get(variant))); break; default: break; @@ -268,10 +259,9 @@ QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *e { QJsonPrivate::Parser parser(json); QJsonDocument result; - const QCborValue val = parser.parse(error); + QCborValue val = parser.parse(error); if (val.isArray() || val.isMap()) { - result.d = std::make_unique(); - result.d->value = val; + result = QJsonDocument(std::move(val)); } else if (!val.isUndefined() && error) { // parsed a valid string/number/bool/null, // but QJsonDocument only stores objects and arrays. @@ -359,10 +349,7 @@ QJsonArray QJsonDocument::array() const */ void QJsonDocument::setObject(const QJsonObject &object) { - if (!d) - d = std::make_unique(); - - d->value = QCborValue::fromJsonValue(object); + *this = QJsonDocument(QCborValue::fromJsonValue(object)); } /*! @@ -372,10 +359,7 @@ void QJsonDocument::setObject(const QJsonObject &object) */ void QJsonDocument::setArray(const QJsonArray &array) { - if (!d) - d = std::make_unique(); - - d->value = QCborValue::fromJsonValue(array); + *this = QJsonDocument(QCborValue::fromJsonValue(array)); } /*! diff --git a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.h b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.h index 8c3163299b..bb761da480 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.h +++ b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsondocument.h @@ -105,7 +105,7 @@ private: const QJsonDocument &rhs) noexcept; Q_DECLARE_EQUALITY_COMPARABLE(QJsonDocument) - QJsonDocument(const QCborValue &data); + inline explicit QJsonDocument(QCborValue data); std::unique_ptr d; }; diff --git a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsonvalue.h b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsonvalue.h index 2a5889f251..4bb3d170a4 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsonvalue.h +++ b/local/recipes/qt/qtbase/source/src/corelib/serialization/qjsonvalue.h @@ -137,9 +137,10 @@ private: static_assert(sizeof(QExplicitlySharedDataPointer) == sizeof(void *)); static_assert(sizeof(QCborValue::Type) == sizeof(QJsonValue::Type)); }; - Q_DECLARE_SHARED(QJsonValue) +Q_CORE_EXPORT size_t qHash(const QJsonValue &value, size_t seed = 0); + class QJsonValueConstRef { public: @@ -177,6 +178,9 @@ public: const QJsonValue operator[](qsizetype i) const { return concrete(*this)[i]; } protected: + friend size_t qHash(const QJsonValueConstRef &key, size_t seed = 0) noexcept + { return QHashPrivate::ex1to2arg(concrete(key), seed); } + friend bool comparesEqual(const QJsonValueConstRef &lhs, const QJsonValueConstRef &rhs) { @@ -339,8 +343,6 @@ inline QJsonValue QCborValueConstRef::toJsonValue() const return concrete().toJsonValue(); } -Q_CORE_EXPORT size_t qHash(const QJsonValue &value, size_t seed = 0); - #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &); #endif diff --git a/local/recipes/qt/qtbase/source/src/corelib/serialization/qtextstream.cpp b/local/recipes/qt/qtbase/source/src/corelib/serialization/qtextstream.cpp index dd216ae3df..6e1b8b62ef 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/serialization/qtextstream.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/serialization/qtextstream.cpp @@ -1635,7 +1635,7 @@ QString QTextStream::read(qint64 maxlen) if (maxlen <= 0) return QString::fromLatin1(""); // empty, not null - return d->read(q26::saturate_cast(maxlen)); + return d->read(q26::saturating_cast(maxlen)); } /*! diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.cpp b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.cpp index ee12f3f8f3..01afc7c44d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.cpp @@ -21,6 +21,7 @@ #if defined(Q_OS_WASM) #include "private/qstdweb_p.h" #endif +#include #ifndef QT_NO_COMPRESS #include @@ -731,7 +732,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel) if (out.data() == nullptr) // allocation failed return tooMuchData(ZLibOp::Compression); - qToBigEndian(q26::saturate_cast(nbytes), out.data()); + qToBigEndian(q26::saturating_cast(nbytes), out.data()); out.size = HeaderSize; return xxflate(ZLibOp::Compression, std::move(out), {data, nbytes}, @@ -3280,8 +3281,7 @@ QByteArray QByteArray::sliced_helper(QByteArray &a, qsizetype pos, qsizetype n) \sa isLower(), toUpper(), {Character Case} */ -template -static QByteArray toCase_template(T &input, uchar (*lookup)(uchar)) +static QByteArray toCase(const QByteArray &input, QByteArray *rvalue, uchar (*lookup)(uchar)) { // find the first bad character in input const char *orig_begin = input.constBegin(); @@ -3295,10 +3295,10 @@ static QByteArray toCase_template(T &input, uchar (*lookup)(uchar)) } if (firstBad == e) - return std::move(input); + return q_choose_copy_move(input, rvalue); // transform the rest - QByteArray s = std::move(input); // will copy if T is const QByteArray + QByteArray s = q_choose_copy_move(input, rvalue); char *b = s.begin(); // will detach if necessary char *p = b + (firstBad - orig_begin); e = b + s.size(); @@ -3309,12 +3309,12 @@ static QByteArray toCase_template(T &input, uchar (*lookup)(uchar)) QByteArray QByteArray::toLower_helper(const QByteArray &a) { - return toCase_template(a, asciiLower); + return toCase(a, nullptr, asciiLower); } QByteArray QByteArray::toLower_helper(QByteArray &a) { - return toCase_template(a, asciiLower); + return toCase(a, &a, asciiLower); } /*! @@ -3331,12 +3331,12 @@ QByteArray QByteArray::toLower_helper(QByteArray &a) QByteArray QByteArray::toUpper_helper(const QByteArray &a) { - return toCase_template(a, asciiUpper); + return toCase(a, nullptr, asciiUpper); } QByteArray QByteArray::toUpper_helper(QByteArray &a) { - return toCase_template(a, asciiUpper); + return toCase(a, &a, asciiUpper); } /*! \fn void QByteArray::clear() @@ -5175,7 +5175,9 @@ emscripten::val QByteArray::toEcmaUint8Array() */ /*! - \fn QByteArray &QByteArray::FromBase64Result::operator*() const + \fn const QByteArray &QByteArray::FromBase64Result::operator*() const & + \fn QByteArray &QByteArray::FromBase64Result::operator*() & + \fn QByteArray &&QByteArray::FromBase64Result::operator*() && Returns the decoded byte array. */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.h b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.h index 7dd8543747..48e4d19fe2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.h +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearray.h @@ -229,7 +229,7 @@ public: [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) && { verify(pos, n); return sliced_helper(*this, pos, n); } [[nodiscard]] QByteArray chopped(qsizetype len) && - { verify(0, len); return std::move(*this).first(size() - len); } + { verify(0, len); chop(len); return std::move(*this); } #endif bool startsWith(QByteArrayView bv) const @@ -795,14 +795,9 @@ public: explicit operator bool() const noexcept { return decodingStatus == QByteArray::Base64DecodingStatus::Ok; } -#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(Q_QDOC) QByteArray &operator*() & noexcept { return decoded; } const QByteArray &operator*() const & noexcept { return decoded; } QByteArray &&operator*() && noexcept { return std::move(decoded); } -#else - QByteArray &operator*() noexcept { return decoded; } - const QByteArray &operator*() const noexcept { return decoded; } -#endif friend inline bool operator==(const QByteArray::FromBase64Result &lhs, const QByteArray::FromBase64Result &rhs) noexcept { diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearrayview.h b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearrayview.h index 7d3e82e72a..971be12bde 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qbytearrayview.h +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qbytearrayview.h @@ -138,15 +138,19 @@ private: { return data; } public: - constexpr QByteArrayView() noexcept - : m_size(0), m_data(nullptr) {} + constexpr QByteArrayView() = default; constexpr QByteArrayView(std::nullptr_t) noexcept : QByteArrayView() {} template = true> constexpr QByteArrayView(const Byte *data, qsizetype len) +#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) + : m_data(castHelper(data)), + m_size((Q_ASSERT(len >= 0), Q_ASSERT(data || !len), len)) {} +#else : m_size((Q_ASSERT(len >= 0), Q_ASSERT(data || !len), len)), m_data(castHelper(data)) {} +#endif template = true> constexpr QByteArrayView(const Byte *first, const Byte *last) @@ -381,8 +385,13 @@ private: Q_DECLARE_STRONGLY_ORDERED(QByteArrayView, char16_t, QT_ASCII_CAST_WARN) #endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) - qsizetype m_size; - const storage_type *m_data; +#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) + const storage_type *m_data = nullptr; + qsizetype m_size = 0; +#else + qsizetype m_size = 0; + const storage_type *m_data = nullptr; +#endif }; Q_DECLARE_TYPEINFO(QByteArrayView, Q_PRIMITIVE_TYPE); diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qlocale_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/text/qlocale_win.cpp index 67dc7a2194..568228ea21 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qlocale_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qlocale_win.cpp @@ -99,7 +99,7 @@ static QVariant nullIfEmpty(T &&value) // For use where we should fall back to CLDR if we got an empty value. if (value.isEmpty()) return {}; - return std::move(value); + return std::forward(value); } } @@ -337,8 +337,7 @@ QVariant QSystemLocalePrivate::groupingSizes() int dataSize = getLocaleInfo(LOCALE_SGROUPING, grouping, int(std::size(grouping))); if (dataSize) { // MS does not seem to include {first} so it will always be NAN. - QString sysGroupingStr = QString::fromWCharArray(grouping, dataSize); - auto tokenized = sysGroupingStr.tokenize(u";"); + auto tokenized = QStringView{grouping, dataSize}.tokenize(u';'); int width[2] = {0, 0}; int index = 0; for (const auto tok : tokenized) { diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qstring.cpp b/local/recipes/qt/qtbase/source/src/corelib/text/qstring.cpp index d89810c77a..e3fab1a2d7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qstring.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qstring.cpp @@ -5239,7 +5239,7 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp Returns a string that contains \a n characters of this string, starting at the specified \a position index up to, but not including, the element - at index position \c {\a position + n}. + at index position \tt {\a position + \a n}. If you know that \a position and \a n cannot be out of bounds, use sliced() instead in new code, because it is faster. @@ -5326,7 +5326,7 @@ QString QString::mid(qsizetype position, qsizetype n) && Returns a string that contains \a n characters of this string, starting at position \a pos up to, but not including, the element at index position - \c {\a pos + n}. + \tt {\a pos + \a n}. \note The behavior is undefined when \a pos < 0, \a n < 0, or \a pos + \a n > size(). @@ -5363,8 +5363,8 @@ QString QString::sliced_helper(QString &str, qsizetype pos, qsizetype n) \since 6.8 Modifies this string to start at position \a pos, up to, but not including, - the character (code point) at index position \c {\a pos + n}; and returns - a reference to this string. + the character (code point) at index position \tt {\a pos + \a n}; and + returns a reference to this string. \note The behavior is undefined if \a pos < 0, \a n < 0, or \a pos + \a n > size(). diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qstring.h b/local/recipes/qt/qtbase/source/src/corelib/text/qstring.h index d79f408816..b8d788e209 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qstring.h +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qstring.h @@ -527,7 +527,7 @@ public: [[nodiscard]] QString sliced(qsizetype pos, qsizetype n) && { verify(pos, n); return sliced_helper(*this, pos, n); } [[nodiscard]] QString chopped(qsizetype n) && - { verify(0, n); return std::move(*this).first(size() - n); } + { verify(0, n); chop(n); return std::move(*this); } #endif bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; [[nodiscard]] bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qstringconverter.cpp b/local/recipes/qt/qtbase/source/src/corelib/text/qstringconverter.cpp index cc673c7bfa..3c848f29d7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qstringconverter.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qstringconverter.cpp @@ -1562,12 +1562,12 @@ QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, quint32 codePage, // Need it in this scope, since we try to decrease our window size if we // encounter an error - int nextIn = q26::saturate_cast(mblen); + int nextIn = q26::saturating_cast(mblen); while (mblen > 0) { std::tie(out, outlen) = growOut(1); // Need space for at least one character if (!out) return {}; - const int nextOut = q26::saturate_cast(outlen); + const int nextOut = q26::saturating_cast(outlen); int len = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, mb, nextIn, out, nextOut); if (len) { mb += nextIn; @@ -1627,7 +1627,7 @@ QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, quint32 codePage, break; } } - nextIn = q26::saturate_cast(mblen); + nextIn = q26::saturating_cast(mblen); } if (sp.isEmpty()) { @@ -1749,7 +1749,7 @@ QByteArray QLocal8Bit::convertFromUnicode_sys(QStringView in, quint32 codePage, }; const auto getNextWindowSize = [&]() { - int nextIn = q26::saturate_cast(uclen); + int nextIn = q26::saturating_cast(uclen); // The Windows API has some issues if the current window ends in the // middle of a surrogate pair, so we avoid that: if (nextIn > 1 && QChar::isHighSurrogate(ch[nextIn - 1])) @@ -1763,7 +1763,7 @@ QByteArray QLocal8Bit::convertFromUnicode_sys(QStringView in, quint32 codePage, std::tie(out, outlen) = growOut(1); // We need at least one byte if (!out) return {}; - const int nextOut = q26::saturate_cast(outlen); + const int nextOut = q26::saturating_cast(outlen); len = WideCharToMultiByte(codePage, 0, ch, nextIn, out, nextOut, nullptr, nullptr); if (len > 0) { ch += nextIn; @@ -2515,7 +2515,7 @@ static int partiallyParsedDataCount(QStringConverter::State *state) return std::max(leftOver, 0); } #endif - return q26::saturate_cast(state->remainingChars); + return q26::saturating_cast(state->remainingChars); } } // namespace QtPrivate @@ -2765,7 +2765,7 @@ auto QStringDecoder::finalize(char16_t *out, qsizetype maxlen) -> FinalizeResult if (isValid()) count = QtPrivate::partiallyParsedDataCount(&state); using Error = FinalizeResult::Error; - const qint16 invalidChars = q26::saturate_cast(state.invalidChars + count); + const qint16 invalidChars = q26::saturating_cast(state.invalidChars + count); if (count == 0 || !out) { resetState(); return {out, invalidChars, invalidChars ? Error::InvalidCharacters : Error::NoError}; @@ -2824,7 +2824,7 @@ auto QStringEncoder::finalize(char *out, qsizetype maxlen) -> QStringEncoder::Fi // some state, otherwise we have nothing to do with count == 0 using Error = FinalizeResult::Error; const bool usesIcu = !!(state.flags & QStringConverter::Flag::UsesIcu) && !!state.d[0]; - const qint16 invalidChars = q26::saturate_cast(state.invalidChars + count); + const qint16 invalidChars = q26::saturating_cast(state.invalidChars + count); if (!isValid() || (!count && !usesIcu) || !out) { resetState(); return {out, invalidChars, invalidChars ? Error::InvalidCharacters : Error::NoError}; diff --git a/local/recipes/qt/qtbase/source/src/corelib/text/qvsnprintf.cpp b/local/recipes/qt/qtbase/source/src/corelib/text/qvsnprintf.cpp index abe3dd6772..37abe48049 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/text/qvsnprintf.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/text/qvsnprintf.cpp @@ -68,7 +68,7 @@ int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap) const auto realSize = ba.size(); int result; if constexpr (sizeof(int) != sizeof(realSize)) { - result = q26::saturate_cast(realSize); + result = q26::saturating_cast(realSize); if (result != realSize) { errno = EOVERFLOW; return -1; diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.cpp b/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.cpp index ea2095150f..5d9e7d9dc0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.cpp @@ -506,7 +506,11 @@ return \c true. If the values are \e not the same, the functions load the current value of this QAtomicInteger into \a currentValue and return \c false. +//![memory-order-3-arg-relaxed] \include qatomic.cpp memory-order-relaxed + If the test-and-set fails, the \a currentValue is loaded with \e relaxed + \l {QAtomicInteger#Memory ordering}{memory ordering} semantics. +//![memory-order-3-arg-relaxed] */ /*! @@ -520,7 +524,11 @@ return \c true. If the values are \e not the same, the functions load the current value of this QAtomicInteger into \a currentValue and return \c false. +//![memory-order-3-arg-acquire] \include qatomic.cpp memory-order-acquire + If the test-and-set fails, the \a currentValue is loaded with \e acquire + \l {QAtomicInteger#Memory ordering}{memory ordering} semantics. +//![memory-order-3-arg-acquire] */ /*! @@ -534,7 +542,11 @@ return \c true. If the values are \e not the same, the functions loads the current value of this QAtomicInteger into \a currentValue and return \c false. +//![memory-order-3-arg-release] \include qatomic.cpp memory-order-release + If the test-and-set fails, the \a currentValue is loaded with \e relaxed + \l {QAtomicInteger#Memory ordering}{memory ordering} semantics. +//![memory-order-3-arg-release] */ /*! @@ -548,7 +560,11 @@ return \c true. If the values are \e not the same, it loads the current value of this QAtomicInteger into \a currentValue and return \c false. +//![memory-order-3-arg-ordered] \include qatomic.cpp memory-order-ordered + If the test-and-set fails, the \a currentValue is loaded with \e acquire + \l {QAtomicInteger#Memory ordering}{memory ordering} semantics. +//![memory-order-3-arg-ordered] */ /*! @@ -1454,6 +1470,10 @@ Atomic test-and-set. + \note If you use this function in a loop, consider using the overload with the + additional \c{T *¤tValue} argument instead, which avoids the extra load() on + failure. + If the current value of this QAtomicPointer is the \a expectedValue, the test-and-set functions assign the \a newValue to this QAtomicPointer and return true. If the values are \e not the same, @@ -1469,6 +1489,10 @@ Atomic test-and-set. + \note If you use this function in a loop, consider using the overload with the + additional \c{T *¤tValue} argument instead, which avoids the extra load() on + failure. + If the current value of this QAtomicPointer is the \a expectedValue, the test-and-set functions assign the \a newValue to this QAtomicPointer and return true. If the values are \e not the same, @@ -1485,6 +1509,10 @@ Atomic test-and-set. + \note If you use this function in a loop, consider using the overload with the + additional \c{T *¤tValue} argument instead, which avoids the extra load() on + failure. + If the current value of this QAtomicPointer is the \a expectedValue, the test-and-set functions assign the \a newValue to this QAtomicPointer and return true. If the values are \e not the same, @@ -1501,6 +1529,10 @@ Atomic test-and-set. + \note If you use this function in a loop, consider using the overload with the + additional \c{T *¤tValue} argument instead, which avoids the extra load() on + failure. + If the current value of this QAtomicPointer is the \a expectedValue, the test-and-set functions assign the \a newValue to this QAtomicPointer and return true. If the values are \e not the same, @@ -1512,6 +1544,58 @@ may not be re-ordered. */ +/*! + \fn template bool QAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue, T *¤tValue) + + Atomic test-and-set. + + If the current value of this QAtomicPointer is the \a expectedValue, the + test-and-set functions assign the \a newValue to this QAtomicPointer and + return \c true. If the values are \e not the same, the functions load the + current value of this QAtomicPointer into \a currentValue and return \c false. + + \include qatomic.cpp memory-order-3-arg-relaxed +*/ + +/*! + \fn template bool QAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue, T *¤tValue) + + Atomic test-and-set. + + If the current value of this QAtomicPointer is the \a expectedValue, the + test-and-set functions assign the \a newValue to this QAtomicPointer and + return \c true. If the values are \e not the same, the functions load the + current value of this QAtomicPointer into \a currentValue and return \c false. + + \include qatomic.cpp memory-order-3-arg-acquire +*/ + +/*! + \fn template bool QAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue, T *¤tValue) + + Atomic test-and-set. + + If the current value of this QAtomicPointer is the \a expectedValue, the + test-and-set functions assign the \a newValue to this QAtomicPointer and + return \c true. If the values are \e not the same, the functions load the + current value of this QAtomicPointer into \a currentValue and return \c false. + + \include qatomic.cpp memory-order-3-arg-release +*/ + +/*! + \fn template bool QAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue, T *¤tValue) + + Atomic test-and-set. + + If the current value of this QAtomicPointer is the \a expectedValue, the + test-and-set functions assign the \a newValue to this QAtomicPointer and + return \c true. If the values are \e not the same, the functions load the + current value of this QAtomicPointer into \a currentValue and return \c false. + + \include qatomic.cpp memory-order-3-arg-ordered +*/ + /*! \fn template bool QAtomicPointer::isFetchAndStoreNative() diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.h b/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.h index 2e62973512..9d0cbaea54 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.h +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qatomic.h @@ -152,6 +152,11 @@ public: bool testAndSetRelease(T *expectedValue, T *newValue); bool testAndSetOrdered(T *expectedValue, T *newValue); + bool testAndSetRelaxed(T *expectedValue, T *newValue, T *¤tValue); + bool testAndSetAcquire(T *expectedValue, T *newValue, T *¤tValue); + bool testAndSetRelease(T *expectedValue, T *newValue, T *¤tValue); + bool testAndSetOrdered(T *expectedValue, T *newValue, T *¤tValue); + static constexpr bool isFetchAndStoreNative(); static constexpr bool isFetchAndStoreWaitFree(); diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_p.h b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_p.h index 41c36e99d3..fc570e7dd3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_p.h @@ -227,8 +227,8 @@ public: void wakeAll(); static void *start(void *arg); - void finish(); // happens early (before thread-local dtors) - void cleanup(); // happens late (as a thread-local dtor, if possible) + void finish(bool = false); // happens early (before thread-local dtors) + void cleanup(); // happens late (as a thread-local dtor, if possible) #endif // Q_OS_UNIX #ifdef Q_OS_WIN diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_unix.cpp b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_unix.cpp index 00d2b87b7e..bc45cf5a89 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_unix.cpp @@ -10,7 +10,6 @@ #include #include "qdebug.h" #include "qloggingcategory.h" -#include "qthreadstorage.h" #include #if defined(Q_OS_WASM) @@ -150,7 +149,7 @@ int pthread_timedjoin_np(...) { return ENOSYS; } // pretend Q_CONSTINIT static thread_local QThreadData *currentThreadData = nullptr; -static void destroy_current_thread_data(QThreadData *data) +static void destroy_current_thread_data(QThreadData *data, bool calledFromExit) { QThread *thread = data->thread.loadAcquire(); @@ -165,7 +164,7 @@ static void destroy_current_thread_data(QThreadData *data) // this is very likely the last reference. These pointers cannot be // null and there is no race. QThreadPrivate *thread_p = static_cast(QObjectPrivate::get(thread)); - thread_p->finish(); + thread_p->finish(calledFromExit); if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) thread_p->cleanup(); } else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) { @@ -193,7 +192,7 @@ static void deref_current_thread_data(QThreadData *data) static void destroy_auxiliary_thread_data(void *p) { auto data = static_cast(p); - destroy_current_thread_data(data); + destroy_current_thread_data(data, false); deref_current_thread_data(data); } @@ -225,7 +224,7 @@ struct QThreadDataDestroyer { // running function-local destructors upon ::exit() if (QThreadData *data = get_thread_data()) - destroy_current_thread_data(data); + destroy_current_thread_data(data, true); } }; }; @@ -284,19 +283,20 @@ QThreadData *QThreadData::currentThreadData() noexcept QThreadData *QThreadData::createCurrentThreadData() { Q_ASSERT(!currentThreadData()); - std::unique_ptr data = std::make_unique(); + + QThreadData *data = new QThreadData(); // This needs to be called prior to new QAdoptedThread() to avoid // recursion (see qobject.cpp). - set_thread_data(data.get()); + set_thread_data(data); QT_TRY { - data->thread.storeRelease(new QAdoptedThread(data.get())); + data->thread.storeRelease(new QAdoptedThread(data)); } QT_CATCH(...) { - clearCurrentThreadData(); + deref_current_thread_data(data); QT_RETHROW; } - return data.release(); + return data; } void QAdoptedThread::init() @@ -472,7 +472,7 @@ void *QThreadPrivate::start(void *arg) return nullptr; } -void QThreadPrivate::finish() +void QThreadPrivate::finish(bool calledFromExit) { QThreadPrivate *d = this; QThread *thr = q_func(); @@ -489,7 +489,7 @@ void QThreadPrivate::finish() emit thr->finished(QThread::QPrivateSignal()); QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); - QThreadStoragePrivate::finish(&d->data->tls); + QThreadStoragePrivate::finish(&d->data->tls, calledFromExit); if constexpr (QT_CONFIG(broken_threadlocal_dtors)) cleanup(); @@ -974,7 +974,7 @@ bool QThreadPrivate::wait(QMutexLocker &locker, QDeadlineTimer deadline) pthread_cleanup_push(&CancelState::run, &nocancel); pthread_t thrId = from_HANDLE(data->threadId.loadRelaxed()); if constexpr (QT_CONFIG(pthread_clockjoin)) - r = pthread_clockjoin_np(thrId, nullptr, SteadyClockClockId, pts); + r = pthread_clockjoin_np(thrId, nullptr, QSteadyClockClockId, pts); else r = pthread_timedjoin_np(thrId, nullptr, pts); Q_ASSERT(r == 0 || r == ETIMEDOUT); diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_win.cpp index f5a7756f2b..2459297b63 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qthread_win.cpp @@ -10,7 +10,6 @@ #include #include "qloggingcategory.h" #include "qmutex.h" -#include "qthreadstorage.h" #include @@ -50,6 +49,7 @@ Q_STATIC_LOGGING_CATEGORY(lcQThread, "qt.core.thread", QtWarningMsg) Q_CONSTINIT static thread_local QThreadData *currentThreadData = nullptr; +static void deref_current_thread_data(QThreadData *data); static void destroy_current_thread_data(void *p) { QThreadData *data = static_cast(p); @@ -66,6 +66,12 @@ static void destroy_current_thread_data(void *p) // have begun destruction; we must not dereference the QThread pointer. } + deref_current_thread_data(data); +} + +// static +void deref_current_thread_data(QThreadData *data) +{ // the QThread object may still have a reference, so this may not delete data->deref(); @@ -107,19 +113,20 @@ QThreadData *QThreadData::currentThreadData() noexcept QThreadData *QThreadData::createCurrentThreadData() { Q_ASSERT(!currentThreadData()); - std::unique_ptr data = std::make_unique(); + + QThreadData *data = new QThreadData(); // This needs to be called prior to new QAdoptedThread() to avoid // recursion (see qobject.cpp). - set_thread_data(data.get()); + set_thread_data(data); QT_TRY { - data->thread.storeRelease(new QAdoptedThread(data.get())); + data->thread.storeRelease(new QAdoptedThread(data)); } QT_CATCH(...) { - clearCurrentThreadData(); + deref_current_thread_data(data); QT_RETHROW; } - return data.release(); + return data; } void QAdoptedThread::init() diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage.cpp b/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage.cpp index afd63b7050..a2061e5d23 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage.cpp @@ -134,10 +134,12 @@ void QThreadStoragePrivate::init() destructors(); } -void QThreadStoragePrivate::finish(QList *tls) +void QThreadStoragePrivate::finish(QList *tls, bool suppressWarnings) { if (tls->isEmpty() || !destructors()) return; // nothing to do + if (!QCoreApplication::instanceExists()) + suppressWarnings = true; DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread()); while (!tls->isEmpty()) { @@ -157,7 +159,7 @@ void QThreadStoragePrivate::finish(QList *tls) locker.unlock(); if (!destructor) { - if (QCoreApplication::instanceExists()) + if (!suppressWarnings) qWarning("QThreadStorage: entry %d destroyed before end of thread %p", i, QThread::currentThread()); continue; diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage_p.h b/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage_p.h index 31aa1a5f4e..2610a49790 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qthreadstorage_p.h @@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE namespace QThreadStoragePrivate { void init(); -void finish(QList *tls); +void finish(QList *tls, bool suppressWarnings = false); } // namespace QThreadStoragePrivate QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/corelib/thread/qyieldcpu.h b/local/recipes/qt/qtbase/source/src/corelib/thread/qyieldcpu.h index ab710ea64e..954c49adce 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/thread/qyieldcpu.h +++ b/local/recipes/qt/qtbase/source/src/corelib/thread/qyieldcpu.h @@ -33,7 +33,9 @@ void qYieldCpu(void) noexcept #endif { -#if __has_builtin(__yield) +#if __has_builtin(__builtin_arm_yield) + __builtin_arm_yield(); +#elif __has_builtin(__yield) __yield(); // Generic #elif defined(_YIELD_PROCESSOR) && defined(Q_CC_MSVC) _YIELD_PROCESSOR(); // Generic; MSVC's @@ -47,9 +49,6 @@ void qYieldCpu(void) _mm_pause(); #elif defined(Q_PROCESSOR_X86) __asm__("pause"); // hopefully asm() works in this compiler - -#elif __has_builtin(__builtin_arm_yield) - __builtin_arm_yield(); #elif defined(Q_PROCESSOR_ARM) && Q_PROCESSOR_ARM >= 7 && defined(Q_CC_GNU) __asm__("yield"); // this works everywhere diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.cpp index 769174972a..7e1d2da1df 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qcalendar.h" #include "qcalendarbackend_p.h" #include "qgregoriancalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.h b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.h index 434f06d67f..807f7a540a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendar.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QCALENDAR_H #define QCALENDAR_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarbackend_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarbackend_p.h index ba586114b8..b880e597d2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarbackend_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarbackend_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QCALENDAR_BACKEND_P_H #define QCALENDAR_BACKEND_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarmath_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarmath_p.h index e3c89429ae..b255f0135f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarmath_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qcalendarmath_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QCALENDARMATH_P_H #define QCALENDARMATH_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime.h b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime.h index f2fbf83ee9..e279442fab 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime.h @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDATETIME_H #define QDATETIME_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime_p.h index a1aa7fd76a..a979d60208 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetime_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QDATETIME_P_H #define QDATETIME_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetimeparser_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetimeparser_p.h index bdac02fd14..c716f1802f 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qdatetimeparser_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qdatetimeparser_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QDATETIMEPARSER_P_H #define QDATETIMEPARSER_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar.cpp index dfb99c5073..4bc6104322 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qgregoriancalendar_p.h" #include "qcalendarmath_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar_p.h index 1093a7b9de..9b88d68b9d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qgregoriancalendar_p.h @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #ifndef QGREGORIAN_CALENDAR_P_H #define QGREGORIAN_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar.cpp index 6a0f22d15d..af4b64faa2 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qhijricalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_data_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_data_p.h index 5c1c18f52c..242e29c230 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_data_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_data_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright © 2004-2023 Unicode, Inc. // SPDX-License-Identifier: Unicode-3.0 +// Qt-Security score:significant reason:default #ifndef QHIJRI_CALENDAR_DATA_P_H #define QHIJRI_CALENDAR_DATA_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_p.h index 6c54b93fac..b2a3f7ea3e 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qhijricalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QHIJRI_CALENDAR_P_H #define QHIJRI_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar.cpp index ac1f97cb6c..6f2bf68ed3 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qislamiccivilcalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar_p.h index 4a4bbcc7ed..26cfb8f66d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qislamiccivilcalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QISLAMIC_CIVIL_CALENDAR_P_H #define QISLAMIC_CIVIL_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar.cpp index 683ce6e771..03ff16ad82 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qjalalicalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_data_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_data_p.h index c0b0d8eec5..6c38d7ba48 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_data_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_data_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright © 2004-2023 Unicode, Inc. // SPDX-License-Identifier: Unicode-3.0 +// Qt-Security score:significant reason:default #ifndef QJALALICALENDAR_DATA_P_H #define QJALALICALENDAR_DATA_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_p.h index 51c89fe297..a200df1103 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qjalalicalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QJALALI_CALENDAR_P_H #define QJALALI_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar.cpp index cf3718f471..0fc125fd8c 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qjuliancalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar_p.h index 95850fd4f9..720dacfb64 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qjuliancalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QJULIAN_CALENDAR_P_H #define QJULIAN_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime.cpp index 609a5a4b37..a8c35fc1d6 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qlocaltime_p.h" #include "qplatformdefs.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime_p.h index 5e31d5e9cc..aab01ab2c5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qlocaltime_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef QLOCALTIME_P_H #define QLOCALTIME_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar.cpp index 14aef83afe..4220d03bca 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar.cpp @@ -1,5 +1,6 @@ // 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qmilankoviccalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar_p.h index c6797ac221..a2563db9fd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qmilankoviccalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QMILANKOVICCALENDAR_CALENDAR_P_H #define QMILANKOVICCALENDAR_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar.cpp index a8ce027275..138cd39f9d 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #include "qglobal.h" #include "qromancalendar_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_data_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_data_p.h index a17a2bbec5..afc6280886 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_data_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_data_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2019 The Qt Company Ltd. // Copyright © 2004-2023 Unicode, Inc. // SPDX-License-Identifier: Unicode-3.0 +// Qt-Security score:significant reason:default #ifndef QROMANCALENDAR_DATA_P_H #define QROMANCALENDAR_DATA_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_p.h index 96501ce701..c64ddf55e5 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qromancalendar_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2020 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 +// Qt-Security score:significant reason:default #ifndef QROMAN_CALENDAR_P_H #define QROMAN_CALENDAR_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.cpp index 7b43aab22d..78c69437a1 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2013 John Layt // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qtimezone.h" #if QT_CONFIG(timezone) diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.h b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.h index f7a5800815..cbc7e5e0fd 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezone.h @@ -1,6 +1,7 @@ // Copyright (C) 2017 The Qt Company Ltd. // Copyright (C) 2013 John Layt // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTIMEZONE_H #define QTIMEZONE_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_data_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_data_p.h index 95b1f91959..a2b1a6789b 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_data_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_data_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2024 The Qt Company Ltd. // Copyright © 2004-2023 Unicode, Inc. // SPDX-License-Identifier: Unicode-3.0 +// Qt-Security score:significant reason:default #ifndef QTIMEZONELOCALE_DATA_P_H #define QTIMEZONELOCALE_DATA_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_p.h index 97c4159b3f..baf307a484 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezonelocale_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #ifndef QTIMEZONELOCALE_P_H #define QTIMEZONELOCALE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_android.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_android.cpp index 838f97c746..c7f3e287cb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_android.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_android.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2014 Drew Parsons // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qtimezone.h" #include "qtimezoneprivate_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_chrono.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_chrono.cpp index 8021233953..8a0c35a241 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_chrono.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_chrono.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2024 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 +// Qt-Security score:significant reason:default #include "qtimezoneprivate_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_data_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_data_p.h index ca12e22a5b..972b7e2eac 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_data_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_data_p.h @@ -2,6 +2,7 @@ // Copyright (C) 2013 John Layt // Copyright © 2004-2023 Unicode, Inc. // SPDX-License-Identifier: Unicode-3.0 +// Qt-Security score:significant reason:default #ifndef QTIMEZONEPRIVATE_DATA_P_H #define QTIMEZONEPRIVATE_DATA_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_icu.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_icu.cpp index 9698143cd3..8a2fb3e5bb 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_icu.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_icu.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2013 John Layt // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #include "qtimezone.h" #include "qtimezoneprivate_p.h" @@ -105,7 +106,8 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal, // Set the date to find the transition for status = U_ZERO_ERROR; - ucal_setMillis(ucal, atMSecsSinceEpoch, &status); + const UDate when = UDate(atMSecsSinceEpoch); + ucal_setMillis(ucal, when, &status); // Find the transition time UDate tranMSecs = 0; @@ -117,7 +119,7 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal, // At the end of time, that can "succeed" with tranMSecs == // atMSecsSinceEpoch, which should be treated as a failure. // (At the start of time, previous correctly fails.) - ok = qint64(tranMSecs) > atMSecsSinceEpoch; + ok = tranMSecs > when; } // Set the transition time to find the offsets for @@ -141,7 +143,7 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal, ucal_close(ucal); if (!U_SUCCESS(status) || !ok) return tran; - tran.atMSecsSinceEpoch = tranMSecs; + tran.atMSecsSinceEpoch = qint64(tranMSecs); tran.offsetFromUtc = utc + dst; tran.standardTimeOffset = utc; tran.daylightTimeOffset = dst; diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_p.h b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_p.h index 9a86ded6ef..79224cb1b7 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_p.h @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2013 John Layt // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QTIMEZONEPRIVATE_P_H diff --git a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_win.cpp b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_win.cpp index 9d37f990cf..ce94db0d1a 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_win.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/time/qtimezoneprivate_win.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2013 John Layt // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qtimezone.h" #include "qtimezoneprivate_p.h" diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qfreelist_p.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qfreelist_p.h index 415d298da6..43d2724023 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qfreelist_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qfreelist_p.h @@ -19,6 +19,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE /*! \internal @@ -210,7 +212,7 @@ inline int QFreeList::next() if (!v) { ElementType* const alloced = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); - if (_v[block].testAndSetRelease(nullptr, alloced, v)) { + if (_v[block]._q_value.compare_exchange_strong(v, alloced, std::memory_order_release, std::memory_order_acquire)) { v = alloced; } else { // race with another thread lost diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qhash.cpp b/local/recipes/qt/qtbase/source/src/corelib/tools/qhash.cpp index fa0d575563..e04248e347 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qhash.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qhash.cpp @@ -1396,10 +1396,17 @@ size_t qHash(long double key, size_t seed) noexcept key += static_cast(0.0); qToUnaligned(key, buffer); - if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian) - memset(buffer, 0, sizeof(long double) - Size); - else - memset(buffer + Size, 0, sizeof(long double) - Size); + // Work around: https://issuetracker.google.com/issues/400937647 + // An over-eager Bionic diagnostic in NDK 30 Clang LLVM 21.0.0: + // "error: 'memset' will set 0 bytes; maybe the arguments got flipped? [-Werror,-Wuser-defined-warnings]"" + // Note! Trying to work around the problem with an if-constexpr does not work. + size_t paddingSize = sizeof(long double) - Size; + if (paddingSize > 0) { + if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian) + (memset)(buffer, 0, paddingSize); + else + (memset)(buffer + Size, 0, paddingSize); + } return murmurhash(buffer, sizeof(long double), seed); } } diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qhashfunctions.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qhashfunctions.h index 8f1394c8ad..651f47e8cf 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qhashfunctions.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qhashfunctions.h @@ -184,6 +184,15 @@ template inline size_t qHash(const T *key, size_t seed = 0) noexcept { return qHash(reinterpret_cast(key), seed); } +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) + +// this used to be matched by the 1-to-2-arg adapter, which mixed the seed in differently +// in Qt 7, when the adapter is gone, this will use the const T* overload above instead +template inline size_t qHash(T *key, size_t seed = 0) noexcept +{ + return qHash(reinterpret_cast(key)) ^ seed; +} +#endif // Qt 6 Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(std::nullptr_t, size_t seed = 0) noexcept { return seed; @@ -222,7 +231,7 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QFlags flags, size_t s // ### Qt 7: remove this "catch-all" overload logic, and require users // to provide the two-argument version of qHash. -#if (QT_VERSION < QT_VERSION_CHECK(7, 0, 0)) && !defined(QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD) +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) // Beware of moving this code from here. It needs to see all the // declarations of qHash overloads for C++ fundamental types *before* // its own declaration. @@ -242,11 +251,22 @@ template && sizeof...(Args) == 0 && !std::is_enum_v, bool> = true> constexpr size_t qHash(const T &t, size_t seed, Args&&...) noexcept(noexcept(qHash(t))) +#ifdef QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD + = delete; +#else { return qHash(t) ^ seed; } +#endif // QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD #endif // < Qt 7 namespace QHashPrivate { +// helper for qHash() calls that used to go via the above 1-to-2-arg adapter +template +constexpr size_t ex1to2arg(const T &key, size_t seed) +{ + return QT7_ONLY(qHash(key, seed)) QT6_ONLY(qHash(key, 0U) ^ seed); +} + namespace detail { // approximates std::equality_comparable_with template diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qmap.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qmap.h index 577be7d35b..9080f99a75 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qmap.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qmap.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -57,23 +58,85 @@ public: Q_ASSERT(m.empty()); size_type result = 0; - const auto &keyCompare = source.key_comp(); - const auto filter = [&result, &key, &keyCompare](const auto &v) - { - if (!keyCompare(key, v.first) && !keyCompare(v.first, key)) { - // keys are equivalent (neither a found it - ++result; - return true; - } - return false; - }; - std::remove_copy_if(source.cbegin(), source.cend(), - std::inserter(m, m.end()), - filter); + const auto keep = [this](auto it) { m.insert(m.cend(), *it); }; + + auto it = source.cbegin(); + const auto end = source.cend(); + const auto &cmp = m.key_comp(); + // Keep all before: + for (; it != end && cmp(it->first, key); ++it) + keep(it); + // Count and skip matches: + for (; it != end && !cmp(key, it->first); ++it) + ++result; + // Keep all after: + for (; it != end; ++it) + keep(it); + return result; } + void copyExceptFor(const Map &source, const iterator &skipit) + { + Q_ASSERT(m.empty()); + + auto it = source.cend(); + const auto end = source.cbegin(); + auto hint = m.end(); + if (it == end) + return; + do { + --it; + if (it == skipit) + continue; + hint = m.emplace_hint(hint, it->first, it->second); + } while (it != end); + } + + // Merges the two sources into this one, giving preference to source2 + void fillWithMergeOf(const Map &source1, const Map &source2) + { + Q_ASSERT(m.empty()); + + auto insertionHint = m.end(); + auto src1It = source1.crbegin(); + const auto src1End = source1.crend(); + auto src2It = source2.crbegin(); + const auto src2End = source2.crend(); + const auto &keyCompare = m.key_comp(); + while (src1It != src1End && src2It != src2End) { + if (keyCompare(src2It->first, src1It->first)) { + insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second); + ++src1It; + } else if (keyCompare(src1It->first, src2It->first)) { + insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second); + ++src2It; + } else { + // Equivalence, insert source2, forget source1 + insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second); + ++src1It; + ++src2It; + } + } + for (; src1It != src1End; ++src1It) + insertionHint = m.emplace_hint(insertionHint, src1It->first, src1It->second); + for (; src2It != src2End; ++src2It) + insertionHint = m.emplace_hint(insertionHint, src2It->first, src2It->second); + } + + // Merge source into this one without changing source as std::map::merge would + void insertMap(const Map &source) + { + Q_ASSERT(!m.empty()); + // copy in reverse order, trying to make effective use of insertionHint. + auto insertionHint = m.end(); + auto it = source.crbegin(); + const auto end = source.crend(); + for (; it != end; ++it) + insertionHint = m.emplace_hint(insertionHint, it->first, it->second); + } + // used in key(T), count(Key, T), find(key, T), etc; returns a // comparator object suitable for algorithms with std::(multi)map // iterators. @@ -280,6 +343,35 @@ public: d.reset(new MapData); } + // A detach for holding an already shared copy, until calling function + // is done using references to keys or values that might reference it. + QMap referenceHoldingDetach() + { + if (!d) { + d.reset(new MapData); + } else if (d.isShared()) { + auto hold = *this; + d.detach(); + return hold; + } + return {}; + } + + // Specialized version of referenceHoldingDetach(), which will not copy key, if copying + QMap referenceHoldingDetachExcept(const Key &key) + { + if (!d) { + d.reset(new MapData); + } else if (d.isShared()) { + auto hold = *this; + QtPrivate::QExplicitlySharedDataPointerV2 newData(new MapData); + newData->copyIfNotEquivalentTo(d->m, key); + d.swap(newData); + return hold; + } + return {}; + } + bool isDetached() const noexcept { return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior... @@ -328,10 +420,45 @@ public: if (!d) return T(); - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - // TODO: improve. There is no need of copying all the - // elements (the one to be removed can be skipped). - detach(); + if (d.isShared()) { + Map m; + // For historic reasons, we always un-share (was: detach()) when + // this function is called, even if `key` isn't found + const auto commit = qScopeGuard([&] { QMap{std::move(m)}.swap(*this); }); + + // This way of copying ought to be O(N) (not NlogN) and not causing + // any rebalancings in `m`, because we build in-order and with hint + // [[citation needed]]. + + const auto keep = [&m] (auto it) { m.insert(m.cend(), *it); }; + + auto it = d->m.cbegin(); + const auto end = d->m.cend(); + const auto cmp = d->m.key_comp(); + while (it != end) { + if (cmp(it->first, key)) { // still before + keep(it); + ++it; + } else if (cmp(key, it->first)) { // after, iow: not found + // This should be faster than an actual range-insert, because + // the latter cannot assume that the input is sorted; we can: + while (it != end) { + keep(it); + ++it; + } + break; + } else { // found! + return [&] { + T r = it->second; // we cannot move (isShared()!) + while (++it != end) + keep(it); + return r; + }(); + } + } + // if we reach here, `key` wasn't found: + return T(); + } #ifdef __cpp_lib_node_extract if (const auto node = d->m.extract(key)) @@ -376,8 +503,7 @@ public: T &operator[](const Key &key) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); auto i = d->m.find(key); if (i == d->m.end()) i = d->m.insert({key, T()}).first; @@ -650,8 +776,7 @@ public: iterator find(const Key &key) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.find(key)); } @@ -669,8 +794,7 @@ public: iterator lowerBound(const Key &key) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.lower_bound(key)); } @@ -683,8 +807,7 @@ public: iterator upperBound(const Key &key) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.upper_bound(key)); } @@ -697,73 +820,77 @@ public: iterator insert(const Key &key, const T &value) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - // TODO: improve. In case of assignment, why copying first? - detach(); + const auto hold = referenceHoldingDetachExcept(key); return iterator(d->m.insert_or_assign(key, value).first); } iterator insert(const_iterator pos, const Key &key, const T &value) { - // TODO: improve. In case of assignment, why copying first? - typename Map::const_iterator dpos; - const auto copy = d.isShared() ? *this : QMap(); // keep `key`/`value` alive across the detach - if (!d || d.isShared()) { - auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; + if (!d) { detach(); - dpos = std::next(d->m.cbegin(), posDistance); - } else { - dpos = pos.i; + return iterator(d->m.emplace(key, value).first); + } else if (d.isShared()) { + auto posDistance = std::distance(d->m.cbegin(), pos.i); + const auto hold = referenceHoldingDetachExcept(key); + auto dpos = std::next(d->m.cbegin(), posDistance); + return iterator(d->m.insert_or_assign(dpos, key, value)); } - return iterator(d->m.insert_or_assign(dpos, key, value)); + return iterator(d->m.insert_or_assign(pos.i, key, value)); } void insert(const QMap &map) { - // TODO: improve. In case of assignment, why copying first? if (map.isEmpty()) return; - detach(); + if (isEmpty()) { + *this = map; + return; + } + + if (d.isShared()) { + QtPrivate::QExplicitlySharedDataPointerV2 newD(new MapData); + const auto commit = qScopeGuard([&] { newD.swap(d); }); + newD->fillWithMergeOf(d->m, map.d->m); + return; + } #ifdef __cpp_lib_node_extract + // Since std::map::merge is destructive only use it when not shared auto copy = map.d->m; - copy.merge(std::move(d->m)); + copy.merge(d->m); d->m = std::move(copy); #else - // this is a std::copy, but we can't use std::inserter (need insert_or_assign...). - // copy in reverse order, trying to make effective use of insertionHint. - auto insertionHint = d->m.end(); - auto mapIt = map.d->m.crbegin(); - auto end = map.d->m.crend(); - for (; mapIt != end; ++mapIt) - insertionHint = d->m.insert_or_assign(insertionHint, mapIt->first, mapIt->second); + QtPrivate::QExplicitlySharedDataPointerV2 newD(new MapData); + const auto commit = qScopeGuard([&] { newD.swap(d); }); + newD->fillWithMergeOf(d->m, map.d->m); + #endif } void insert(QMap &&map) { - if (!map.d || map.d->m.empty()) - return; - - if (map.d.isShared()) { + if (map.isEmpty() || map.d.isShared()) { // fall back to a regular copy insert(map); return; } - detach(); + // Otherwise insert into map, and do a swap on return + const auto commit = qScopeGuard([&] { map.swap(*this); }); + if (isEmpty()) + return; + + if (d.isShared()) { + map.d->insertMap(d->m); + return; + } #ifdef __cpp_lib_node_extract map.d->m.merge(std::move(d->m)); - *this = std::move(map); #else // same as above - auto insertionHint = d->m.end(); - auto mapIt = map.d->m.crbegin(); - auto end = map.d->m.crend(); - for (; mapIt != end; ++mapIt) - insertionHint = d->m.insert_or_assign(insertionHint, std::move(mapIt->first), std::move(mapIt->second)); + map.d->insertMap(d->m); #endif } @@ -776,8 +903,7 @@ public: std::pair equal_range(const Key &akey) { - const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); auto result = d->m.equal_range(akey); return {iterator(result.first), iterator(result.second)}; } @@ -959,6 +1085,31 @@ public: d.reset(new MapData); } + // A detach for holding an already shared copy, until calling function + // is done using references to keys or values that might reference it. + [[nodiscard]] QMultiMap referenceHoldingDetach() + { + if (!d) { + d.reset(new MapData); + } else if (d.isShared()) { + auto hold = *this; + d.detach(); + return hold; + } + return {}; + } + + // Specialized version of referenceHoldingDetach(), which will not copy skipit, if copying + [[nodiscard]] QMultiMap referenceHoldingDetachExceptFor(const typename Map::iterator &skipit) + { + Q_ASSERT(d.isShared()); + auto hold = *this; + QtPrivate::QExplicitlySharedDataPointerV2 newData(new MapData); + newData->copyExceptFor(d->m, skipit); + d.swap(newData); + return hold; + } + bool isDetached() const noexcept { return d ? !d.isShared() : false; // false makes little sense, but that's shared_null's behavior... @@ -1001,22 +1152,41 @@ public: if (!d) return 0; - // key and value may belong to this map. As such, we need to copy - // them to ensure they stay valid throughout the iteration below - // (which may destroy them) - const Key keyCopy = key; - const T valueCopy = value; - - // TODO: improve. Copy over only the elements not to be removed. - detach(); - size_type result = 0; const auto &keyCompare = d->m.key_comp(); - auto i = d->m.find(keyCopy); - const auto e = d->m.end(); + if (d.isShared()) { + QtPrivate::QExplicitlySharedDataPointerV2 newData(new MapData); + const auto keep = [&newData](auto it) { newData->m.insert(newData->m.cend(), *it); }; - while (i != e && !keyCompare(keyCopy, i->first)) { + auto it = d->m.cbegin(); + const auto end = d->m.cend(); + for (; it != end && keyCompare(it->first, key); ++it) + keep(it); + // Keep matching keys if value match, otherwise skip and count + for (; it != end && !keyCompare(key, it->first); ++it) { + if (!(it->second == value)) + keep(it); + else + ++result; + } + for (; it != end; ++it) + keep(it); + + d.swap(newData); + return result; + } + + // d->m.erase_if(....) would be nice, but that's C++20. + // So let's do like find(keyCopy, valueCopy): + auto [i, e] = d->m.equal_range(key); + if (i == e) + return result; + + // value may belong to this map. As such, we need to copy it to ensure + // it stays valid throughout the iteration below (which may destroy it) + const T valueCopy = value; + while (i != e) { if (i->second == valueCopy) { i = d->m.erase(i); ++result; @@ -1039,11 +1209,11 @@ public: if (!d) return T(); - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach - - // TODO: improve. There is no need of copying all the - // elements (the one to be removed can be skipped). - detach(); + if (d.isShared()) { + auto i = d->m.find(key); + const auto hold = referenceHoldingDetachExceptFor(i); + return i->second; + } #ifdef __cpp_lib_node_extract if (const auto node = d->m.extract(key)) @@ -1388,8 +1558,7 @@ public: iterator find(const Key &key) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.find(key)); } @@ -1407,9 +1576,7 @@ public: iterator find(const Key &key, const T &value) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach - - detach(); + const auto hold = referenceHoldingDetach(); auto range = d->m.equal_range(key); auto i = std::find_if(range.first, range.second, @@ -1441,8 +1608,7 @@ public: iterator lowerBound(const Key &key) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.lower_bound(key)); } @@ -1455,8 +1621,7 @@ public: iterator upperBound(const Key &key) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); return iterator(d->m.upper_bound(key)); } @@ -1469,8 +1634,7 @@ public: iterator insert(const Key &key, const T &value) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); // note that std::multimap inserts at the end of an equal_range for a key, // QMultiMap at the beginning. auto i = d->m.lower_bound(key); @@ -1479,16 +1643,17 @@ public: iterator insert(const_iterator pos, const Key &key, const T &value) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach - typename Map::const_iterator dpos; - if (!d || d.isShared()) { - auto posDistance = d ? std::distance(d->m.cbegin(), pos.i) : 0; - detach(); - dpos = std::next(d->m.cbegin(), posDistance); - } else { - dpos = pos.i; + if (!d) { + d.reset(new MapData); + return iterator(d->m.insert({ key, value })); + } else if (d.isShared()) { + auto posDistance = std::distance(d->m.cbegin(), pos.i); + auto hold = referenceHoldingDetach(); + auto dpos = std::next(d->m.cbegin(), posDistance); + return iterator(d->m.insert(dpos, {key, value})); } - return iterator(d->m.insert(dpos, {key, value})); + + return iterator(d->m.insert(pos.i, {key, value})); } #if QT_DEPRECATED_SINCE(6, 0) @@ -1518,14 +1683,18 @@ public: iterator replace(const Key &key, const T &value) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key`/`value` alive across the detach - - // TODO: improve. No need of copying and then overwriting. - detach(); + if (!d) { + d.reset(new MapData); + return iterator(d->m.insert({ key, value })); + } + auto i = d->m.find(key); + if (d.isShared()) { + const auto hold = referenceHoldingDetachExceptFor(i); + return iterator(d->m.insert({ key, value })); + } // Similarly, improve here (e.g. lower_bound and hinted insert); // there's no insert_or_assign on multimaps - auto i = d->m.find(key); if (i != d->m.end()) i->second = value; else @@ -1540,8 +1709,7 @@ public: std::pair equal_range(const Key &akey) { - const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach - detach(); + const auto hold = referenceHoldingDetach(); auto result = d->m.equal_range(akey); return {iterator(result.first), iterator(result.second)}; } diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qminimalflatset_p.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qminimalflatset_p.h index 0d435c63c9..96a807fd49 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qminimalflatset_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qminimalflatset_p.h @@ -69,7 +69,7 @@ public: iterator begin() const { return c.cbegin(); } iterator end() const { return c.cend(); } iterator cbegin() const { return begin(); } - iterator cend() const { return cend(); } + iterator cend() const { return end(); } reverse_iterator rbegin() const { return c.crbegin(); } reverse_iterator rend() const { return c.crend(); } diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qoffsetstringarray_p.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qoffsetstringarray_p.h index e4a8c0ec6b..0519e6e971 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qoffsetstringarray_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qoffsetstringarray_p.h @@ -25,11 +25,6 @@ #include #include #include -#include - -#ifdef __cpp_concepts -# include -#endif class tst_QOffsetStringArray; @@ -41,8 +36,7 @@ QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wstringop-overread") #endif - -template +template class QOffsetStringArray { static auto viewType_helper() @@ -62,6 +56,7 @@ class QOffsetStringArray public: using Char = typename StaticString::value_type; using View = typename decltype(viewType_helper())::type; + static constexpr typename OffsetList::value_type MaxElementLength = LongestElement; constexpr QOffsetStringArray(const StaticString &string, const OffsetList &offsets) : m_string(string), m_offsets(offsets) @@ -118,6 +113,7 @@ template constexpr auto minifyValue() template constexpr auto makeOffsetStringArray(const Char (&...entries)[Nx]) { + constexpr int LongestElement = std::max({ Nx... }) - 1; constexpr size_t StringLength = (Nx + ...); using OffsetType = decltype(QtPrivate::minifyValue()); @@ -136,7 +132,10 @@ constexpr auto makeOffsetStringArray(const Char (&...entries)[Nx]) q20::copy_n(strings[i], length, staticString.begin() + offsetList[i]); } - return QOffsetStringArray(staticString, offsetList); + using StaticString = decltype(staticString); + using OffsetList = decltype(offsetList); + using R = QOffsetStringArray; + return R(staticString, offsetList); } } // namespace QtPrivate diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qquasivirtual_impl.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qquasivirtual_impl.h index 706d00ec1a..136c4c5ff9 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qquasivirtual_impl.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qquasivirtual_impl.h @@ -33,8 +33,7 @@ void applyIndexSwitch(size_t index, Applier&& applier, std::index_sequence(((Is == index ? (applier(std::integral_constant{}), true) : false) - || ...)); + static_cast(((Is == index && (applier(std::integral_constant{}), true)) || ...)); } template @@ -138,7 +137,7 @@ public: struct Deleter { - void operator () (QQuasiVirtualInterface* self) const { self->call(); } + void operator () (QQuasiVirtualInterface* self) const { self->template call(); } }; protected: diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.h b/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.h index cc3576ecf3..2348d9fa44 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.h @@ -394,11 +394,20 @@ public: // the moved-from state is the empty state, so we're good with the clear() here: clear(); Q_ASSERT(capacity() >= Prealloc); + const auto thisInlineStorage = this->array; const auto otherInlineStorage = other.array; if (other.ptr != otherInlineStorage) { - // heap storage: steal the external buffer, reset other to otherInlineStorage - this->a = std::exchange(other.a, Prealloc); - this->ptr = std::exchange(other.ptr, otherInlineStorage); + // heap storage: steal the external buffer + if (this->ptr == thisInlineStorage) { + // we were using inline storage; reset other to otherInlineStorage + this->a = std::exchange(other.a, Prealloc); + this->ptr = std::exchange(other.ptr, otherInlineStorage); + } else { + // both were using heap storage; do a PURE_SWAP (note we already + // destroyed all elements of *this, so this is just memory, so ok!): + std::swap(this->a, other.a); + qt_ptr_swap(this->ptr, other.ptr); + } } else { // inline storage: move into our storage (doesn't matter whether inline or external) QtPrivate::q_uninitialized_relocate_n(other.data(), other.size(), data()); diff --git a/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.qdoc b/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.qdoc index 3beb623ac5..74886a7e23 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.qdoc +++ b/local/recipes/qt/qtbase/source/src/corelib/tools/qvarlengtharray.qdoc @@ -304,8 +304,10 @@ Returns a reference to the item at index position \a i. +//! [valid-i] \a i must be a valid index position in the array (i.e., 0 <= \a i < size()). +//! [valid-i] \sa data(), at() */ @@ -445,8 +447,7 @@ Returns a reference to the item at index position \a i. - \a i must be a valid index position in the array (i.e., 0 <= \a i - < size()). + \include qvarlengtharray.qdoc valid-i \sa value(), operator[]() */ @@ -582,8 +583,7 @@ \since 4.8 Replaces the item at index position \a i with \a value. - \a i must be a valid index position in the array (i.e., 0 <= \a - i < size()). + \include qvarlengtharray.qdoc valid-i \sa operator[](), remove() */ @@ -593,9 +593,13 @@ \overload \since 4.8 - Removes \a count elements from the middle of the array, starting at + Removes \a count elements from the array, starting at index position \a i. + \include qvarlengtharray.qdoc valid-i + \a count must be <= size() - \a i. + \a i == size() is allowed if \a count == 0. + \sa insert(), replace() */ diff --git a/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf.cpp b/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf.cpp index 1d50b830e4..e4382510d0 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf.cpp +++ b/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #define BUILD_LIBRARY diff --git a/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf_p.h b/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf_p.h index 70d00d018c..a7ef6c6280 100644 --- a/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf_p.h +++ b/local/recipes/qt/qtbase/source/src/corelib/tracing/qctf_p.h @@ -1,5 +1,6 @@ // Copyright (C) 2022 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 +// Qt-Security score:significant reason:default #ifndef Q_CTF_H #define Q_CTF_H diff --git a/local/recipes/qt/qtbase/source/src/dbus/qdbusargument.cpp b/local/recipes/qt/qtbase/source/src/dbus/qdbusargument.cpp index 42b13d9d9b..45a678538f 100644 --- a/local/recipes/qt/qtbase/source/src/dbus/qdbusargument.cpp +++ b/local/recipes/qt/qtbase/source/src/dbus/qdbusargument.cpp @@ -38,18 +38,18 @@ QByteArray QDBusArgumentPrivate::createSignature(QMetaType type) return ""; QByteArray signature; - QDBusMarshaller *marshaller = new QDBusMarshaller; - marshaller->ba = &signature; + const bool ok = [&signature, &type] { + QDBusMarshaller marshaller; + marshaller.ba = &signature; - // run it - QVariant v{type}; - QDBusArgument arg(marshaller); - QDBusMetaType::marshall(arg, v.metaType(), v.constData()); - arg.d = nullptr; + // run it + QVariant v{type}; + QDBusArgument arg(&marshaller); + QDBusMetaType::marshall(arg, v.metaType(), v.constData()); + arg.d = nullptr; - // delete it - bool ok = marshaller->ok; - delete marshaller; + return marshaller.ok; + }(); if (signature.isEmpty() || !ok || !QDBusUtil::isValidSingleSignature(QString::fromLatin1(signature))) { qWarning("QDBusMarshaller: type '%s' produces invalid D-Bus signature '%s' " diff --git a/local/recipes/qt/qtbase/source/src/dbus/qdbusintegrator.cpp b/local/recipes/qt/qtbase/source/src/dbus/qdbusintegrator.cpp index d61a431e90..420fb3921c 100644 --- a/local/recipes/qt/qtbase/source/src/dbus/qdbusintegrator.cpp +++ b/local/recipes/qt/qtbase/source/src/dbus/qdbusintegrator.cpp @@ -1132,7 +1132,7 @@ void QDBusConnectionPrivate::closeConnection() } } - for (QDBusPendingCallPrivate *call : pendingCalls) { + for (QDBusPendingCallPrivate *call : std::as_const(pendingCalls)) { if (!call->ref.deref()) delete call; } @@ -1422,15 +1422,21 @@ bool QDBusConnectionPrivate::activateInternalFilters(const ObjectTreeNode &node, if (msg.member() == "Get"_L1 && msg.signature() == "ss"_L1) { QDBusMessage reply = qDBusPropertyGet(node, msg); - send(reply); + if (!msg.isDelayedReply()) { + send(reply); + } return true; } else if (msg.member() == "Set"_L1 && msg.signature() == "ssv"_L1) { QDBusMessage reply = qDBusPropertySet(node, msg); - send(reply); + if (!msg.isDelayedReply()) { + send(reply); + } return true; } else if (msg.member() == "GetAll"_L1 && msg.signature() == "s"_L1) { QDBusMessage reply = qDBusPropertyGetAll(node, msg); - send(reply); + if (!msg.isDelayedReply()) { + send(reply); + } return true; } diff --git a/local/recipes/qt/qtbase/source/src/dbus/qdbusmetaobject.cpp b/local/recipes/qt/qtbase/source/src/dbus/qdbusmetaobject.cpp index 149392f9c3..70b861e793 100644 --- a/local/recipes/qt/qtbase/source/src/dbus/qdbusmetaobject.cpp +++ b/local/recipes/qt/qtbase/source/src/dbus/qdbusmetaobject.cpp @@ -173,6 +173,7 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature, // type is still unknown or doesn't match back to the signature that it // was expected to, so synthesize a fake type typeName = "QDBusRawType<0x" + signature.toHex() + ">*"; + Q_ASSERT(typeName == QMetaObject::normalizedType(typeName)); type = registerComplexDBusType(typeName); } @@ -195,6 +196,7 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature, type = qMetaTypeId(); } else { result.name = "{D-Bus type \"" + signature + "\"}"; + result.name = QMetaObject::normalizedType(result.name); type = registerComplexDBusType(result.name); } } else { diff --git a/local/recipes/qt/qtbase/source/src/dbus/qdbusmetatype.cpp b/local/recipes/qt/qtbase/source/src/dbus/qdbusmetatype.cpp index 033668a515..47828521d5 100644 --- a/local/recipes/qt/qtbase/source/src/dbus/qdbusmetatype.cpp +++ b/local/recipes/qt/qtbase/source/src/dbus/qdbusmetatype.cpp @@ -456,7 +456,7 @@ const char *QDBusMetaType::typeToSignature(QMetaType type) { QReadLocker locker(&ct->lock); auto it = ct->hash.constFind(type.id()); - if (it == ct->hash.end()) + if (it == ct->hash.cend()) return nullptr; const QDBusCustomTypeInfo &info = *it; diff --git a/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt index 14b8e50adb..2d6b9e7f27 100644 --- a/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt @@ -64,7 +64,6 @@ qt_internal_add_module(Gui QMAKE_MODULE_CONFIG "${qmake_module_config}" SOURCES - painting/qt_float16_shims.c compat/removed_api.cpp image/qabstractfileiconengine.cpp image/qabstractfileiconengine_p.h image/qabstractfileiconprovider.cpp image/qabstractfileiconprovider.h image/qabstractfileiconprovider_p.h diff --git a/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt.orig b/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt.orig new file mode 100644 index 0000000000..57991122a6 --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/gui/CMakeLists.txt.orig @@ -0,0 +1,1138 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_find_package(X11_XCB MODULE) +qt_find_package(WrapHarfbuzz MODULE PROVIDED_TARGETS WrapHarfbuzz::WrapHarfbuzz) +qt_find_package(WrapPNG MODULE PROVIDED_TARGETS WrapPNG::WrapPNG) +qt_find_package(WrapFreetype MODULE PROVIDED_TARGETS WrapFreetype::WrapFreetype) + +if (QT_FEATURE_gui) + if(QT_QPA_PLATFORMS) + list(GET QT_QPA_PLATFORMS 0 _default_platform) + elseif(WIN32) + set(_default_platform "windows") + elseif(ANDROID) + set(_default_platform "android") + elseif(MACOS) + set(_default_platform "cocoa") + elseif(UIKIT) + set(_default_platform "ios") + elseif(WATCHOS) + set(_default_platform "minimal") + elseif(QNX) + set(_default_platform "qnx") + elseif(INTEGRITY) + set(_default_platform "eglfs") + elseif(HAIKU) + set(_default_platform "haiku") + elseif(WASM) + set(_default_platform "wasm") + else() + set(_default_platform "xcb") + endif() + + set(QT_QPA_DEFAULT_PLATFORM "${_default_platform}" CACHE STRING "QPA default platform") + if(NOT "${QT_QPA_DEFAULT_PLATFORM}" IN_LIST QT_QPA_PLATFORMS) + list(APPEND QT_QPA_PLATFORMS "${QT_QPA_DEFAULT_PLATFORM}") + set(QT_QPA_PLATFORMS "${QT_QPA_PLATFORMS}" CACHE STRING + "QPA platforms deployed by default" FORCE) + endif() +endif() + +# Silence warnings in 3rdparty code +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set_source_files_properties(../3rdparty/md4c/md4c.c PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + set_source_files_properties(../3rdparty/md4c/md4c.c PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers -Wno-missing-braces") +endif() + +# Silence AUTOMOC warning 'No relevant classes found. No output generated.' +if (NOT QT_FEATURE_wayland) + set_source_files_properties(kernel/qplatformwindow_p.h + PROPERTIES SKIP_AUTOMOC TRUE) +endif() + +unset(qmake_module_config) +if(QT_FEATURE_opengl) + list(APPEND qmake_module_config opengl) +endif() + +qt_internal_add_module(Gui + PLUGIN_TYPES accessiblebridge platforms platforms/darwin xcbglintegrations platformthemes platforminputcontexts generic iconengines imageformats egldeviceintegrations wayland-graphics-integration-client wayland-decoration-client wayland-shell-integration + + QMAKE_MODULE_CONFIG "${qmake_module_config}" + SOURCES + compat/removed_api.cpp + image/qabstractfileiconengine.cpp image/qabstractfileiconengine_p.h + image/qabstractfileiconprovider.cpp image/qabstractfileiconprovider.h image/qabstractfileiconprovider_p.h + image/qbitmap.cpp image/qbitmap.h + image/qbmphandler.cpp image/qbmphandler_p.h + image/qfonticonengine.cpp image/qfonticonengine_p.h + image/qicon.cpp image/qicon.h image/qicon_p.h + image/qiconengine.cpp image/qiconengine.h image/qiconengine_p.h + image/qiconengineplugin.cpp image/qiconengineplugin.h + image/qiconloader.cpp image/qiconloader_p.h + image/qimage.cpp image/qimage.h image/qimage_p.h + image/qimage_conversions.cpp + image/qimageiohandler.cpp image/qimageiohandler.h + image/qimagepixmapcleanuphooks.cpp image/qimagepixmapcleanuphooks_p.h + image/qimagereader.cpp image/qimagereader.h + image/qimagereaderwriterhelpers.cpp image/qimagereaderwriterhelpers_p.h + image/qimagewriter.cpp image/qimagewriter.h + image/qpaintengine_pic.cpp image/qpaintengine_pic_p.h + image/qpicture.cpp image/qpicture.h image/qpicture_p.h + image/qpixmap.cpp image/qpixmap.h + image/qpixmap_blitter.cpp image/qpixmap_blitter_p.h + image/qpixmap_raster.cpp image/qpixmap_raster_p.h + image/qpixmapcache.cpp image/qpixmapcache.h image/qpixmapcache_p.h + image/qplatformpixmap.cpp image/qplatformpixmap.h + image/qppmhandler.cpp image/qppmhandler_p.h + image/qxbmhandler.cpp image/qxbmhandler_p.h + image/qxpmhandler.cpp image/qxpmhandler_p.h + kernel/qaccessibilityhints.cpp kernel/qaccessibilityhints.h kernel/qaccessibilityhints_p.h + kernel/qclipboard.cpp kernel/qclipboard.h + kernel/qcursor.cpp kernel/qcursor.h kernel/qcursor_p.h + kernel/qeventpoint.cpp kernel/qeventpoint.h kernel/qeventpoint_p.h + kernel/qevent.cpp kernel/qevent.h kernel/qevent_p.h + kernel/qgenericplugin.cpp kernel/qgenericplugin.h + kernel/qgenericpluginfactory.cpp kernel/qgenericpluginfactory.h + kernel/qguiapplication.cpp kernel/qguiapplication.h kernel/qguiapplication_p.h kernel/qguiapplication_platform.h + kernel/qguivariant.cpp + kernel/qhighdpiscaling.cpp kernel/qhighdpiscaling_p.h + kernel/qinputdevice.cpp kernel/qinputdevice.h kernel/qinputdevice_p.h + kernel/qinputdevicemanager.cpp kernel/qinputdevicemanager_p.h + kernel/qinputdevicemanager_p_p.h + kernel/qinputmethod.cpp kernel/qinputmethod.h kernel/qinputmethod_p.h + kernel/qinternalmimedata.cpp kernel/qinternalmimedata_p.h + kernel/qkeymapper.cpp kernel/qkeymapper_p.h + kernel/qoffscreensurface.cpp kernel/qoffscreensurface.h kernel/qoffscreensurface_p.h + kernel/qoffscreensurface_platform.h + kernel/qopenglcontext.h + kernel/qpaintdevicewindow.cpp kernel/qpaintdevicewindow.h kernel/qpaintdevicewindow_p.h + kernel/qpalette.cpp kernel/qpalette.h kernel/qpalette_p.h + kernel/qpixelformat.cpp kernel/qpixelformat.h + kernel/qplatformclipboard.cpp kernel/qplatformclipboard.h + kernel/qplatformcursor.cpp kernel/qplatformcursor.h + kernel/qplatformdialoghelper.cpp kernel/qplatformdialoghelper.h + kernel/qplatformgraphicsbuffer.cpp kernel/qplatformgraphicsbuffer.h + kernel/qplatformgraphicsbufferhelper.cpp kernel/qplatformgraphicsbufferhelper.h + kernel/qplatforminputcontext.cpp kernel/qplatforminputcontext.h kernel/qplatforminputcontext_p.h + kernel/qplatforminputcontextfactory.cpp kernel/qplatforminputcontextfactory_p.h + kernel/qplatforminputcontextplugin.cpp kernel/qplatforminputcontextplugin_p.h + kernel/qplatformintegration.cpp kernel/qplatformintegration.h + kernel/qplatformintegrationfactory.cpp kernel/qplatformintegrationfactory_p.h + kernel/qplatformintegrationplugin.cpp kernel/qplatformintegrationplugin.h + kernel/qplatformkeymapper.cpp kernel/qplatformkeymapper.h + kernel/qplatformmenu.cpp kernel/qplatformmenu.h kernel/qplatformmenu_p.h + kernel/qplatformnativeinterface.cpp kernel/qplatformnativeinterface.h + kernel/qplatformoffscreensurface.cpp kernel/qplatformoffscreensurface.h + kernel/qplatformopenglcontext.h + kernel/qplatformscreen.cpp kernel/qplatformscreen.h kernel/qplatformscreen_p.h + kernel/qplatformservices.cpp kernel/qplatformservices.h + kernel/qplatformsessionmanager.cpp kernel/qplatformsessionmanager.h + kernel/qplatformsharedgraphicscache.cpp kernel/qplatformsharedgraphicscache.h + kernel/qplatformsurface.cpp kernel/qplatformsurface.h + kernel/qplatformsystemtrayicon.cpp kernel/qplatformsystemtrayicon.h + kernel/qplatformtheme.cpp kernel/qplatformtheme.h kernel/qplatformtheme_p.h + kernel/qplatformthemefactory.cpp kernel/qplatformthemefactory_p.h + kernel/qplatformthemeplugin.cpp kernel/qplatformthemeplugin.h + kernel/qplatformwindow.cpp kernel/qplatformwindow.h kernel/qplatformwindow_p.h + kernel/qpointingdevice.cpp kernel/qpointingdevice.h kernel/qpointingdevice_p.h + kernel/qrasterwindow.cpp kernel/qrasterwindow.h + kernel/qscreen.cpp kernel/qscreen.h kernel/qscreen_p.h kernel/qscreen_platform.h + kernel/qsessionmanager.cpp kernel/qsessionmanager.h kernel/qsessionmanager_p.h + kernel/qstylehints.cpp kernel/qstylehints.h kernel/qstylehints_p.h + kernel/qsurface.cpp kernel/qsurface.h + kernel/qsurfaceformat.cpp kernel/qsurfaceformat.h + kernel/qtestsupport_gui.cpp kernel/qtestsupport_gui.h + kernel/qtguiglobal.h kernel/qtguiglobal_p.h + kernel/qwindow.cpp kernel/qwindow.h kernel/qwindow_p.h + kernel/qwindowdefs.h + kernel/qwindowsysteminterface.cpp kernel/qwindowsysteminterface.h kernel/qwindowsysteminterface_p.h + math3d/qgenericmatrix.cpp math3d/qgenericmatrix.h + math3d/qmatrix4x4.cpp math3d/qmatrix4x4.h + math3d/qquaternion.cpp math3d/qquaternion.h + math3d/qvector2d.h + math3d/qvector3d.h + math3d/qvector4d.h + math3d/qvectornd.cpp math3d/qvectornd.h + opengl/qopengl.h + opengl/qopenglext.h + opengl/qopenglfunctions.h + opengl/qopenglextrafunctions.h + painting/qbackingstore.cpp painting/qbackingstore.h + painting/qbackingstoredefaultcompositor.cpp painting/qbackingstoredefaultcompositor_p.h + painting/qbackingstorerhisupport.cpp painting/qbackingstorerhisupport_p.h + painting/qbezier.cpp painting/qbezier_p.h + painting/qblendfunctions.cpp painting/qblendfunctions_p.h + painting/qblittable.cpp painting/qblittable_p.h + painting/qbrush.cpp painting/qbrush.h + painting/qcolor.cpp painting/qcolor.h painting/qcolor_p.h + painting/qcolorclut_p.h + painting/qcolormatrix_p.h + painting/qcolorspace.cpp painting/qcolorspace.h painting/qcolorspace_p.h + painting/qcolortransferfunction_p.h + painting/qcolortransfergeneric_p.h + painting/qcolortransfertable_p.h + painting/qcolortransform.cpp painting/qcolortransform.h painting/qcolortransform_p.h + painting/qcolortrc_p.h + painting/qcolortrclut.cpp painting/qcolortrclut_p.h + painting/qcompositionfunctions.cpp + painting/qcosmeticstroker.cpp painting/qcosmeticstroker_p.h + painting/qcmyk_p.h + painting/qdatabuffer_p.h + painting/qdrawhelper_p.h + painting/qdrawhelper_x86_p.h + painting/qdrawingprimitive_sse2_p.h + painting/qdrawhelper_loongarch64_p.h + painting/qdrawingprimitive_lsx_p.h + painting/qemulationpaintengine.cpp painting/qemulationpaintengine_p.h + painting/qfixed_p.h + painting/qgrayraster.c painting/qgrayraster_p.h + painting/qicc.cpp painting/qicc_p.h + painting/qimageeffects.cpp + painting/qimagescale.cpp painting/qimagescale_p.h + painting/qmath_p.h + painting/qmemrotate.cpp painting/qmemrotate_p.h + painting/qoutlinemapper.cpp painting/qoutlinemapper_p.h + painting/qpagedpaintdevice.cpp painting/qpagedpaintdevice.h painting/qpagedpaintdevice_p.h + painting/qpagelayout.cpp painting/qpagelayout.h + painting/qpageranges.cpp painting/qpageranges.h painting/qpageranges_p.h + painting/qpagesize.cpp painting/qpagesize.h + painting/qpaintdevice.cpp painting/qpaintdevice.h + painting/qpaintengine.cpp painting/qpaintengine.h painting/qpaintengine_p.h + painting/qpaintengine_blitter.cpp painting/qpaintengine_blitter_p.h + painting/qpaintengine_raster.cpp painting/qpaintengine_raster_p.h + painting/qpaintengineex.cpp painting/qpaintengineex_p.h + painting/qpainter.cpp painting/qpainter.h painting/qpainter_p.h + painting/qpainterstateguard.cpp painting/qpainterstateguard.h + painting/qpainterpath.cpp painting/qpainterpath.h painting/qpainterpath_p.h + painting/qpathclipper.cpp painting/qpathclipper_p.h + painting/qpathsimplifier.cpp painting/qpathsimplifier_p.h + painting/qpdf.cpp painting/qpdf_p.h + painting/qpdfoutputintent.cpp painting/qpdfoutputintent.h + painting/qpdfwriter.cpp painting/qpdfwriter.h + painting/qpen.cpp painting/qpen.h painting/qpen_p.h + painting/qpixellayout.cpp painting/qpixellayout_p.h + painting/qplatformbackingstore.cpp painting/qplatformbackingstore.h + painting/qpolygon.cpp painting/qpolygon.h + painting/qrasterdefs_p.h + painting/qrasterizer.cpp painting/qrasterizer_p.h + painting/qrbtree_p.h + painting/qregion.cpp painting/qregion.h + painting/qrgb.h + painting/qrgba64.h painting/qrgba64_p.h + painting/qrgbafloat.h + painting/qstroker.cpp painting/qstroker_p.h + painting/qtextureglyphcache.cpp painting/qtextureglyphcache_p.h + painting/qtransform.cpp painting/qtransform.h + painting/qtriangulatingstroker.cpp painting/qtriangulatingstroker_p.h + painting/qtriangulator.cpp painting/qtriangulator_p.h + painting/qvectorpath_p.h + rhi/qrhi.cpp rhi/qrhi.h rhi/qrhi_platform.h rhi/qrhi_p.h + rhi/qrhinull.cpp rhi/qrhinull_p.h + rhi/qshader.cpp rhi/qshader.h rhi/qshader_p.h + rhi/qshaderdescription.cpp rhi/qshaderdescription.h rhi/qshaderdescription_p.h + text/qabstracttextdocumentlayout.cpp text/qabstracttextdocumentlayout.h text/qabstracttextdocumentlayout_p.h + text/qcolrpaintgraphrenderer.cpp text/qcolrpaintgraphrenderer_p.h + text/qdistancefield.cpp text/qdistancefield_p.h + text/qfont.cpp text/qfont.h text/qfont_p.h + text/qfontdatabase.cpp text/qfontdatabase.h text/qfontdatabase_p.h + text/qfontengine.cpp text/qfontengine_p.h + text/qfontengineglyphcache.cpp text/qfontengineglyphcache_p.h + text/qfontinfo.h + text/qfontmetrics.cpp text/qfontmetrics.h + text/qfontsubset.cpp text/qfontsubset_p.h + text/qfontvariableaxis.cpp text/qfontvariableaxis.h + text/qfragmentmap.cpp text/qfragmentmap_p.h + text/qglyphrun.cpp text/qglyphrun.h text/qglyphrun_p.h + text/qinputcontrol.cpp text/qinputcontrol_p.h + text/qplatformfontdatabase.cpp text/qplatformfontdatabase.h + text/qrawfont.cpp text/qrawfont.h text/qrawfont_p.h + text/qstatictext.cpp text/qstatictext.h text/qstatictext_p.h + text/qsyntaxhighlighter.cpp text/qsyntaxhighlighter.h + text/qtextcursor.cpp text/qtextcursor.h text/qtextcursor_p.h + text/qtextdocument.cpp text/qtextdocument.h text/qtextdocument_p.cpp text/qtextdocument_p.h + text/qtextdocumentfragment.cpp text/qtextdocumentfragment.h text/qtextdocumentfragment_p.h + text/qtextdocumentlayout.cpp text/qtextdocumentlayout_p.h + text/qtextdocumentwriter.cpp text/qtextdocumentwriter.h + text/qtextengine.cpp text/qtextengine_p.h + text/qtextformat.cpp text/qtextformat.h text/qtextformat_p.h + text/qtexthtmlparser.cpp text/qtexthtmlparser_p.h + text/qtextimagehandler.cpp text/qtextimagehandler_p.h + text/qtextlayout.cpp text/qtextlayout.h + text/qtextlist.cpp text/qtextlist.h + text/qtextobject.cpp text/qtextobject.h text/qtextobject_p.h + text/qtextoption.cpp text/qtextoption.h + text/qtexttable.cpp text/qtexttable.h text/qtexttable_p.h + util/qabstractlayoutstyleinfo.cpp util/qabstractlayoutstyleinfo_p.h + util/qastchandler.cpp util/qastchandler_p.h + util/qdesktopservices.cpp util/qdesktopservices.h + util/qgridlayoutengine.cpp util/qgridlayoutengine_p.h + util/qhexstring_p.h + util/qktxhandler.cpp util/qktxhandler_p.h + util/qlayoutpolicy.cpp util/qlayoutpolicy_p.h + util/qpkmhandler.cpp util/qpkmhandler_p.h + util/qtexturefiledata.cpp util/qtexturefiledata_p.h + util/qtexturefilehandler_p.h + util/qtexturefilereader.cpp util/qtexturefilereader_p.h + util/qvalidator.cpp util/qvalidator.h + DEFINES + QT_NO_CONTEXTLESS_CONNECT + QT_NO_FOREACH + QT_NO_URL_CAST_FROM_STRING + QT_NO_USING_NAMESPACE + QT_USE_NODISCARD_FILE_OPEN + QT_QPA_DEFAULT_PLATFORM_NAME="${QT_QPA_DEFAULT_PLATFORM}" + INCLUDE_DIRECTORIES + ../3rdparty/VulkanMemoryAllocator + ../3rdparty/D3D12MemoryAllocator + LIBRARIES + Qt::CorePrivate + PUBLIC_LIBRARIES + Qt::Core + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + NO_PCH_SOURCES + compat/removed_api.cpp + painting/qdrawhelper.cpp + PRECOMPILED_HEADER + "kernel/qt_gui_pch.h" + QPA_HEADER_FILTERS + "(^|/)qplatform.+\\.h$|(^|/)qwindowsystem.+\\.h$" + RHI_HEADER_FILTERS + "(^|/)qrhi\\.h$|(^|/)qrhi_platform\\.h$|(^|/)qshader\\.h$|(^|/)qshaderdescription\\.h$" + ATTRIBUTION_FILE_DIR_PATHS + rhi + opengl + painting + text + ../3rdparty/VulkanMemoryAllocator + ../3rdparty/emoji-segmenter + # Used by qbrush.cpp -> painting/webgradients.cpp which is generated by the JS script + ../../util/gradientgen + ELF_LINKER_DYNAMIC_LIST + QtGui.dynlist.in +) + +# Resources: +if(QT_FEATURE_pdf) + set_source_files_properties("../3rdparty/icc/sRGB2014.icc" + PROPERTIES QT_RESOURCE_ALIAS "sRGB2014.icc" + ) + set(qpdf_resource_files + "../3rdparty/icc/sRGB2014.icc" + ) + qt_internal_extend_target(Gui + ATTRIBUTION_FILE_DIR_PATHS + ../3rdparty/icc + ) + + qt_internal_add_resource(Gui "qpdf" + PREFIX + "/qpdf/" + BASE + "painting" + FILES + ${qpdf_resource_files} + ) +endif() + +if(UNIX AND NOT APPLE) + set_target_properties(Gui PROPERTIES UNITY_BUILD OFF) # X11 define clashes. +endif() + +qt_internal_add_resource(Gui "gui_shaders" + PREFIX + "/qt-project.org/gui" + FILES + "painting/shaders/backingstorecompose.vert.qsb" + "painting/shaders/backingstorecompose.frag.qsb" +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_standarditemmodel + SOURCES + itemmodels/qstandarditemmodel.cpp itemmodels/qstandarditemmodel.h itemmodels/qstandarditemmodel_p.h +) + +# With qmake, gui's opengl.pri used CONFIG += opengl, where opengl.prf +# used direct public linkage against either libGLESv2 or libGL, depending +# on the opengl _feature_. This is done by hand now here (where the +# feature is available). +# On Windows with 'dynamic' OpenGL we must not link to opengl32. +# DO NOT MOVE THIS TO THE BEGINNING OF THE FILE, the feature variables are not +# available until the qt_internal_add_module call. +if(QT_FEATURE_opengl) + if(QT_FEATURE_opengles2) + find_package(GLESv2) + target_link_libraries(Gui PUBLIC GLESv2::GLESv2) + + if(TARGET PlatformGraphics::PlatformGraphics) + qt_internal_extend_target(Gui + LIBRARIES + PlatformGraphics::PlatformGraphics + ) + endif() + elseif(NOT QT_FEATURE_opengl_dynamic) + target_link_libraries(Gui PUBLIC WrapOpenGL::WrapOpenGL) + endif() +endif() + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengl + SOURCES + kernel/qopenglcontext.cpp kernel/qopenglcontext_p.h + kernel/qopenglcontext_platform.h + kernel/qplatformopenglcontext.cpp + opengl/qopengl.cpp opengl/qopengl_p.h + opengl/qopenglextensions_p.h + opengl/qopenglfunctions.cpp + opengl/qopenglprogrambinarycache.cpp opengl/qopenglprogrambinarycache_p.h + rhi/qrhigles2.cpp rhi/qrhigles2_p.h +) + +qt_internal_extend_target(Gui CONDITION MACOS + SOURCES + platform/macos/qcocoanativeinterface.mm + platform/macos/qmacstyle_p.h + LIBRARIES + ${FWAppKit} + ${FWCarbon} + PUBLIC_LIBRARIES + ${FWAppKit} +) + +qt_internal_extend_target(Gui CONDITION MACOS AND QT_FEATURE_opengl + PUBLIC_LIBRARIES + ${FWOpenGL} +) + +qt_internal_extend_target(Gui CONDITION UIKIT + SOURCES + platform/ios/qiosnativeinterface.cpp +) + +qt_internal_extend_target(Gui CONDITION WASM + SOURCES + platform/wasm/qwasmnativeinterface.cpp +) + +qt_internal_extend_target(Gui CONDITION APPLE + SOURCES + image/qimage_darwin.mm + painting/qcoregraphics.mm painting/qcoregraphics_p.h + painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h + painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h + platform/darwin/qmacmimeregistry.mm platform/darwin/qmacmimeregistry_p.h + platform/darwin/qutimimeconverter.mm platform/darwin/qutimimeconverter.h + platform/darwin/qapplekeymapper.mm platform/darwin/qapplekeymapper_p.h + platform/darwin/qapplefileiconengine.mm platform/darwin/qapplefileiconengine_p.h + platform/darwin/qappleiconengine.mm platform/darwin/qappleiconengine_p.h + text/coretext/qcoretextfontdatabase.mm text/coretext/qcoretextfontdatabase_p.h + text/coretext/qfontengine_coretext.mm text/coretext/qfontengine_coretext_p.h + LIBRARIES + ${FWCoreFoundation} + ${FWCoreGraphics} + ${FWCoreText} + ${FWFoundation} + ${FWAccelerate} + PUBLIC_LIBRARIES + ${FWImageIO} +) + +qt_internal_extend_target(Gui CONDITION APPLE AND QT_FEATURE_metal + SOURCES + platform/darwin/qmetallayer.mm platform/darwin/qmetallayer_p.h + LIBRARIES + ${FWQuartzCore} +) + +qt_internal_extend_target(Gui CONDITION QNX + SOURCES + painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h + painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_animation + SOURCES + animation/qguivariantanimation.cpp +) + +qt_internal_extend_target(Gui CONDITION WIN32 + SOURCES + image/qpixmap_win.cpp image/qpixmap_win_p.h + kernel/qwindowdefs_win.h + platform/windows/qwindowsguieventdispatcher.cpp platform/windows/qwindowsguieventdispatcher_p.h + platform/windows/qwindowsmimeconverter.h platform/windows/qwindowsmimeconverter.cpp + platform/windows/qwindowsnativeinterface.cpp + platform/windows/qwindowsthemecache.cpp platform/windows/qwindowsthemecache_p.h + rhi/qrhid3d11.cpp rhi/qrhid3d11_p.h + rhi/qrhid3d12.cpp rhi/qrhid3d12_p.h + rhi/qrhid3dhelpers.cpp rhi/qrhid3dhelpers_p.h + rhi/vs_test_p.h + rhi/cs_mipmap_p.h rhi/cs_mipmap_3d_p.h + ../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.h + ../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp + rhi/qdxgivsyncservice_p.h rhi/qdxgivsyncservice.cpp + rhi/qdxgihdrinfo_p.h rhi/qdxgihdrinfo.cpp + text/windows/qwindowsfontdatabase.cpp text/windows/qwindowsfontdatabase_p.h + text/windows/qwindowsfontdatabasebase.cpp text/windows/qwindowsfontdatabasebase_p.h + text/windows/qwindowsfontengine.cpp text/windows/qwindowsfontengine_p.h + text/windows/qwindowsnativeimage.cpp text/windows/qwindowsnativeimage_p.h + LIBRARIES + advapi32 + gdi32 + ole32 + shell32 + user32 + uxtheme + PUBLIC_LIBRARIES + d3d11 + dxgi + dxguid + d3d12 + NO_UNITY_BUILD_SOURCES + rhi/qrhid3d11.cpp rhi/qrhid3d12.cpp # duplicate aligned() etc + text/windows/qwindowsfontdatabasebase.cpp # duplicate struct OS2Table + ATTRIBUTION_FILE_DIR_PATHS + ../3rdparty/D3D12MemoryAllocator +) + +if(QT_FEATURE_graphicsframecapture) + qt_internal_extend_target(Gui + SOURCES + util/qgraphicsframecapture_p.h util/qgraphicsframecapture.cpp + util/qgraphicsframecapture_p_p.h + ) + + qt_internal_extend_target(Gui CONDITION (WIN32 OR (UNIX AND NOT APPLE)) AND QT_FEATURE_library + LIBRARIES + RenderDoc::RenderDoc + SOURCES + util/qgraphicsframecapturerenderdoc_p_p.h util/qgraphicsframecapturerenderdoc.cpp + ) + + qt_internal_extend_target(Gui CONDITION IOS OR MACOS + SOURCES + util/qgraphicsframecapturemetal_p_p.h util/qgraphicsframecapturemetal.mm + PUBLIC_LIBRARIES + ${FWMetal} + ) +endif() + +if(QT_FEATURE_egl) + qt_find_package(EGL MODULE) +endif() + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_egl + SOURCES + opengl/platform/egl/qeglconvenience.cpp opengl/platform/egl/qeglconvenience_p.h + opengl/platform/egl/qeglstreamconvenience.cpp opengl/platform/egl/qeglstreamconvenience_p.h + opengl/platform/egl/qt_egl_p.h + LIBRARIES + EGL::EGL +) + +# These two headers are always installed, their contents are guarded with +# "#if QT_CONFIG(accessibility)", so if QT_FEATURE_accessibility is not +# enabled, they are just duds. +qt_internal_extend_target(Gui + SOURCES + accessible/qaccessible.h accessible/qplatformaccessibility.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_accessibility + SOURCES + accessible/qaccessible.cpp accessible/qaccessible_base.h + accessible/qaccessiblebridge.cpp accessible/qaccessiblebridge.h + accessible/qaccessiblebridgeutils.cpp accessible/qaccessiblebridgeutils_p.h + accessible/qaccessiblecache.cpp accessible/qaccessiblecache_p.h + accessible/qaccessiblehelper.cpp accessible/qaccessiblehelper_p.h + accessible/qaccessibleobject.cpp accessible/qaccessibleobject.h + accessible/qaccessibleplugin.cpp accessible/qaccessibleplugin.h + accessible/qplatformaccessibility.cpp +) + +qt_internal_extend_target(Gui CONDITION APPLE AND QT_FEATURE_accessibility + SOURCES + accessible/qaccessiblecache_mac.mm + LIBRARIES + ${FWFoundation} +) + +if(QT_FEATURE_accessibility AND QT_FEATURE_accessibility_atspi_bridge) + set(atspi_accessibility ON) +else() + set(atspi_accessibility OFF) +endif() + +qt_internal_extend_target(Gui CONDITION atspi_accessibility + SOURCES + accessible/linux/atspiadaptor.cpp accessible/linux/atspiadaptor_p.h + accessible/linux/dbusconnection.cpp accessible/linux/dbusconnection_p.h + accessible/linux/qspi_constant_mappings.cpp accessible/linux/qspi_constant_mappings_p.h + accessible/linux/qspi_struct_marshallers.cpp accessible/linux/qspi_struct_marshallers_p.h + accessible/linux/qspiaccessiblebridge.cpp accessible/linux/qspiaccessiblebridge_p.h + accessible/linux/qspiapplicationadaptor.cpp accessible/linux/qspiapplicationadaptor_p.h + accessible/linux/qspidbuscache.cpp accessible/linux/qspidbuscache_p.h + accessible/linux/qspimatchrulematcher.cpp accessible/linux/qspimatchrulematcher_p.h + DBUS_ADAPTOR_SOURCES + accessible/linux/dbusxml/Cache.xml + accessible/linux/dbusxml/DeviceEventController.xml + DBUS_ADAPTOR_FLAGS + "-i" "QtGui/private/qspi_struct_marshallers_p.h" + "--namespace" "QtGuiPrivate" + DBUS_INTERFACE_SOURCES + accessible/linux/dbusxml/Bus.xml + accessible/linux/dbusxml/Socket.xml + accessible/linux/dbusxml/org.freedesktop.DBus.Properties.xml + DBUS_INTERFACE_FLAGS + "-i" "QtGui/private/qspi_struct_marshallers_p.h" + "--namespace" "QtGuiPrivate" +) + +if(atspi_accessibility) + qt_internal_add_target_include_dirs(Gui PkgConfig::ATSPI2) +endif() + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_action + SOURCES + kernel/qaction.cpp kernel/qaction.h kernel/qaction_p.h + kernel/qactiongroup.cpp kernel/qactiongroup.h kernel/qactiongroup_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_draganddrop + SOURCES + kernel/qdnd.cpp kernel/qdnd_p.h + kernel/qdrag.cpp kernel/qdrag.h + kernel/qplatformdrag.cpp kernel/qplatformdrag.h + kernel/qshapedpixmapdndwindow.cpp kernel/qshapedpixmapdndwindow_p.h + kernel/qsimpledrag.cpp kernel/qsimpledrag_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_shortcut + SOURCES + kernel/qkeysequence.cpp kernel/qkeysequence.h kernel/qkeysequence_p.h + kernel/qshortcut.cpp kernel/qshortcut.h kernel/qshortcut_p.h + kernel/qshortcutmap.cpp kernel/qshortcutmap_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_movie + SOURCES + image/qmovie.cpp image/qmovie.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_png + SOURCES + image/qpnghandler.cpp image/qpnghandler_p.h + LIBRARIES + WrapPNG::WrapPNG +) + +qt_internal_extend_target(Gui + CONDITION + QT_FEATURE_png AND WIN32 AND MINGW AND + (CMAKE_CXX_COMPILER_VESION VERSION_EQUAL "8.1.0") + COMPILE_OPTIONS + -fno-reorder-blocks-and-partition +) + +if(TEST_architecture_arch STREQUAL x86_64) + qt_internal_extend_target(Gui + SOURCES + painting/qdrawhelper_sse2.cpp + ) +else() + qt_internal_add_simd_part(Gui SIMD sse2 + SOURCES + painting/qdrawhelper_sse2.cpp + ) +endif() + +qt_internal_add_simd_part(Gui SIMD ssse3 + SOURCES + image/qimage_ssse3.cpp + painting/qdrawhelper_ssse3.cpp +) + +qt_internal_add_simd_part(Gui SIMD sse4_1 + SOURCES + painting/qdrawhelper_sse4.cpp + painting/qimagescale_sse4.cpp +) + +qt_internal_add_simd_part(Gui SIMD arch_haswell + SOURCES + painting/qdrawhelper_avx2.cpp + EXCLUDE_OSX_ARCHITECTURES + arm64 +) + +qt_internal_add_simd_part(Gui SIMD neon + SOURCES + image/qimage_neon.cpp + painting/qdrawhelper_neon.cpp painting/qdrawhelper_neon_p.h + painting/qimagescale_neon.cpp +) + +qt_internal_add_simd_part(Gui SIMD lsx + SOURCES + image/qimage_lsx.cpp + painting/qdrawhelper_lsx.cpp + painting/qimagescale_lsx.cpp +) + +qt_internal_add_simd_part(Gui SIMD lasx + SOURCES + image/qimage_lasx.cpp + painting/qdrawhelper_lasx.cpp +) + +if(NOT ANDROID) + qt_internal_add_simd_part(Gui SIMD mips_dsp + SOURCES + painting/qdrawhelper_mips_dsp.cpp painting/qdrawhelper_mips_dsp_p.h + painting/qdrawhelper_mips_dsp_asm.S + painting/qt_mips_asm_dsp_p.h + ) + + qt_internal_add_simd_part(Gui SIMD mips_dspr2 + SOURCES + image/qimage_mips_dspr2.cpp + image/qimage_mips_dspr2_asm.S + painting/qdrawhelper_mips_dspr2_asm.S + ) +endif() + +qt_internal_extend_target(Gui CONDITION ANDROID + SOURCES + platform/android/qandroidnativeinterface.cpp + painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h + painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h +) + +qt_internal_extend_target(Gui CONDITION ANDROID AND (TEST_architecture_arch STREQUAL arm64 OR TEST_architecture_arch STREQUAL arm) + SOURCES + image/qimage_neon.cpp + painting/qdrawhelper_neon.cpp painting/qdrawhelper_neon_p.h + painting/qimagescale_neon.cpp +) + +qt_internal_extend_target(Gui CONDITION ANDROID AND (TEST_architecture_arch STREQUAL i386 OR TEST_architecture_arch STREQUAL x86_64) + SOURCES + image/qimage_ssse3.cpp + painting/qdrawhelper_sse2.cpp + painting/qdrawhelper_ssse3.cpp + DEFINES + QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE2 + QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSE3 + QT_COMPILER_SUPPORTS_SSSE3 QT_COMPILER_SUPPORTS_SSSE3 +) + +if (MINGW AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.1.0) + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86048 + set_source_files_properties(image/qpnghandler.cpp + PROPERTIES COMPILE_OPTIONS -fno-reorder-blocks-and-partition + ) +endif() + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_harfbuzz + SOURCES + text/qharfbuzzng.cpp text/qharfbuzzng_p.h + LIBRARIES + WrapHarfbuzz::WrapHarfbuzz +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_harfbuzz AND UIKIT + LIBRARIES + ${FWCoreText} +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_textodfwriter + SOURCES + text/qtextodfwriter.cpp text/qtextodfwriter_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_textmarkdownreader + SOURCES + text/qtextmarkdownimporter.cpp text/qtextmarkdownimporter_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_system_textmarkdownreader AND QT_FEATURE_textmarkdownreader + LIBRARIES + WrapSystemMd4c::WrapSystemMd4c +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_textmarkdownreader AND NOT QT_FEATURE_system_textmarkdownreader + SOURCES + ../3rdparty/md4c/md4c.c ../3rdparty/md4c/md4c.h + DEFINES + MD4C_USE_UTF8 + INCLUDE_DIRECTORIES + ../3rdparty/md4c + ATTRIBUTION_FILE_DIR_PATHS + ../3rdparty/md4c +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_textmarkdownwriter + SOURCES + text/qtextmarkdownwriter.cpp text/qtextmarkdownwriter_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_cssparser + SOURCES + painting/qcssutil.cpp painting/qcssutil_p.h + text/qcssparser.cpp text/qcssparser_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_freetype + SOURCES + text/freetype/qfontengine_ft.cpp text/freetype/qfontengine_ft_p.h + text/freetype/qfreetypefontdatabase.cpp text/freetype/qfreetypefontdatabase_p.h + LIBRARIES + WrapFreetype::WrapFreetype +) + +qt_internal_extend_target(Gui CONDITION UNIX AND NOT APPLE + SOURCES + text/unix/qgenericunixfontdatabase_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_fontconfig AND QT_FEATURE_freetype AND UNIX AND NOT APPLE + SOURCES + text/unix/qfontconfigdatabase.cpp text/unix/qfontconfigdatabase_p.h + text/unix/qfontenginemultifontconfig.cpp text/unix/qfontenginemultifontconfig_p.h + LIBRARIES + Fontconfig::Fontconfig +) + +qt_internal_extend_target(Gui CONDITION APPLE AND NOT MACOS + LIBRARIES + ${FWUIKit} +) + +qt_internal_extend_target(Gui CONDITION APPLE AND QT_FEATURE_freetype + LIBRARIES + WrapFreetype::WrapFreetype +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_freetype AND WIN32 + SOURCES + text/windows/qwindowsfontdatabase_ft.cpp text/windows/qwindowsfontdatabase_ft_p.h + LIBRARIES + WrapFreetype::WrapFreetype +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 + SOURCES + text/windows/qwindowsfontenginedirectwrite.cpp text/windows/qwindowsfontenginedirectwrite_p.h + NO_UNITY_BUILD_SOURCES + text/windows/qwindowsfontenginedirectwrite.cpp # conflicts + LIBRARIES + d2d1 +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite3 AND WIN32 + SOURCES + text/windows/qwindowsdirectwritefontdatabase.cpp text/windows/qwindowsdirectwritefontdatabase_p.h + LIBRARIES + dwrite +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 AND NOT QT_FEATURE_directwrite3 + LIBRARIES + dwrite +) + +qt_internal_extend_target(Gui CONDITION MINGW AND WIN32 + LIBRARIES + uuid +) + +# Only enable the Pixman draw-helpers on platforms that support the GAS syntax of their asm files +# Note: These helpers are only used for 16-bit surfaces, so excluding them does not generally +# exclude neon-drawhelpers on these platforms. +if(UNIX AND NOT ANDROID AND NOT INTEGRITY AND NOT (TEST_architecture_arch STREQUAL "arm64") AND NOT UIKIT AND NOT QT_IS_MACOS_UNIVERSAL) + qt_internal_extend_target(Gui + DEFINES + ENABLE_PIXMAN_DRAWHELPERS + ATTRIBUTION_FILE_DIR_PATHS + ../3rdparty/pixman + ) + qt_internal_add_simd_part(Gui SIMD neon + SOURCES + ../3rdparty/pixman/pixman-arm-neon-asm.S + painting/qdrawhelper_neon_asm.S + ) +endif() + +qt_internal_extend_target(Gui CONDITION ANDROID AND TEST_architecture_arch STREQUAL x86_64 + SOURCES + painting/qdrawhelper_sse4.cpp + painting/qimagescale_sse4.cpp + DEFINES + QT_COMPILER_SUPPORTS_SSE4_1 + QT_COMPILER_SUPPORTS_SSE4_2 +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_system_zlib + LIBRARIES + WrapZLIB::WrapZLIB +) + +qt_internal_extend_target(Gui CONDITION NOT QT_FEATURE_system_zlib + INCLUDE_DIRECTORIES + ../3rdparty/zlib/src + ATTRIBUTION_FILE_DIR_PATHS + ../3rdparty/zlib +) + +qt_internal_extend_target(Gui CONDITION NOT QT_FEATURE_system_zlib + LIBRARIES + Qt::Core +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_undocommand + SOURCES + util/qundostack.cpp util/qundostack.h util/qundostack_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_undogroup + SOURCES + util/qundogroup.cpp util/qundogroup.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengl AND QT_FEATURE_xlib AND NOT QT_FEATURE_opengles2 + SOURCES + opengl/platform/unix/qglxconvenience.cpp opengl/platform/unix/qglxconvenience_p.h + LIBRARIES + X11::X11 +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengles2 + SOURCES + opengl/qopengles2ext.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_egl AND QT_FEATURE_opengl AND NOT WASM + SOURCES + opengl/platform/egl/qeglpbuffer.cpp opengl/platform/egl/qeglpbuffer_p.h + opengl/platform/egl/qeglplatformcontext.cpp opengl/platform/egl/qeglplatformcontext_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_egl AND NOT QT_FEATURE_egl_x11 + DEFINES + QT_EGL_NO_X11 +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_dlopen AND QT_FEATURE_egl + LIBRARIES + ${CMAKE_DL_LIBS} +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_standarditemmodel + SOURCES + itemmodels/qstandarditemmodel.cpp itemmodels/qstandarditemmodel.h itemmodels/qstandarditemmodel_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_filesystemmodel + SOURCES + itemmodels/qfileinfogatherer.cpp itemmodels/qfileinfogatherer_p.h + itemmodels/qfilesystemmodel.cpp itemmodels/qfilesystemmodel.h itemmodels/qfilesystemmodel_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_vulkan + SOURCES + rhi/qrhivulkan.cpp rhi/qrhivulkan_p.h + vulkan/qbasicvulkanplatforminstance.cpp vulkan/qbasicvulkanplatforminstance_p.h + vulkan/qplatformvulkaninstance.cpp vulkan/qplatformvulkaninstance.h + vulkan/qvulkandefaultinstance.cpp vulkan/qvulkandefaultinstance_p.h + vulkan/qvulkanfunctions.cpp + vulkan/qvulkaninstance.cpp vulkan/qvulkaninstance.h vulkan/qvulkaninstance_p.h + vulkan/qvulkanwindow.cpp vulkan/qvulkanwindow.h vulkan/qvulkanwindow_p.h + ATTRIBUTION_FILE_DIR_PATHS + vulkan +) +if(QT_FEATURE_vulkan) + qt_internal_add_target_include_dirs_and_optionally_propagate( + Gui WrapVulkanHeaders::WrapVulkanHeaders) +endif() + +# We must always generate syncqt-injected header files, +# because we added a custom command earlier for those for framework builds. +set(vulkan_fun "qvulkanfunctions.h") +set(vulkan_fun_p "qvulkanfunctions_p.h") +set(vulkan_fun_outputs "vulkan/${vulkan_fun}" "vulkan/${vulkan_fun_p}") +set(vulkan_fun_command_content COMMAND "${CMAKE_COMMAND}" -E make_directory "vulkan") +if (QT_FEATURE_vulkan) + set(vulkan_fun_p_cpp "qvulkanfunctions_p.cpp") + list(APPEND vulkan_fun_outputs "vulkan/${vulkan_fun_p_cpp}") + + if(NOT "${QT_HOST_PATH}" STREQUAL "") + set(host_executable_suffix "") + if(CMAKE_HOST_WIN32) + set(host_executable_suffix ".exe") + endif() + qt_internal_get_host_info_var_prefix(host_info_var_prefix) + qt_path_join(qvkgen + "${QT_HOST_PATH}" + "${${host_info_var_prefix}_LIBEXECDIR}" + "qvkgen${host_executable_suffix}") + elseif(QT_OPTIONAL_TOOLS_PATH) + qt_path_join(qvkgen + "${QT_OPTIONAL_TOOLS_PATH}" + "${INSTALL_LIBEXECDIR}" + "qvkgen${host_executable_suffix}") + else() + set(qvkgen "${QT_CMAKE_EXPORT_NAMESPACE}::qvkgen") + endif() + + list(APPEND vulkan_fun_command_content + COMMAND "${qvkgen}" + "${CMAKE_CURRENT_SOURCE_DIR}/vulkan/vk.xml" + "${CMAKE_CURRENT_SOURCE_DIR}/vulkan/licenseheader.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/vulkan/qvulkanfunctions" + DEPENDS vulkan/vk.xml ${qvkgen} + COMMENT "Generating vulkan data" + ) + + qt_internal_extend_target(Gui + SOURCES + "${CMAKE_CURRENT_BINARY_DIR}/vulkan/${vulkan_fun}" + "${CMAKE_CURRENT_BINARY_DIR}/vulkan/${vulkan_fun_p}" + "${CMAKE_CURRENT_BINARY_DIR}/vulkan/${vulkan_fun_p_cpp}" + ) +else() + foreach(file ${vulkan_fun_outputs}) + list(APPEND vulkan_fun_command_content + COMMAND "${CMAKE_COMMAND}" -E touch "${file}") + endforeach() +endif() +add_custom_command( + OUTPUT ${vulkan_fun_outputs} + ${vulkan_fun_command_content} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + VERBATIM +) +set_source_files_properties(${vulkan_fun_outputs} PROPERTIES _qt_syncqt_exclude_from_docs TRUE) + +qt_internal_extend_target(Gui CONDITION WASM + SOURCES + platform/wasm/qlocalfileapi.cpp platform/wasm/qlocalfileapi_p.h + platform/wasm/qwasmlocalfileaccess.cpp platform/wasm/qwasmlocalfileaccess_p.h +) + +qt_internal_extend_target(Gui CONDITION UNIX + SOURCES + platform/unix/qunixnativeinterface.cpp +) + +qt_internal_extend_target(Gui CONDITION UNIX AND NOT WASM + SOURCES + platform/unix/qgenericunixeventdispatcher.cpp platform/unix/qgenericunixeventdispatcher_p.h + platform/unix/qunixeventdispatcher.cpp + platform/unix/qunixeventdispatcher_qpa_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_glib AND UNIX + SOURCES + platform/unix/qeventdispatcher_glib.cpp platform/unix/qeventdispatcher_glib_p.h + LIBRARIES + GLIB2::GLIB2 +) + +qt_internal_extend_target(Gui CONDITION UNIX AND (QT_FEATURE_xcb OR NOT UIKIT) + SOURCES + platform/unix/qdesktopunixservices.cpp platform/unix/qdesktopunixservices_p.h +) + +qt_internal_extend_target(Gui CONDITION UNIX AND (QT_FEATURE_xcb) + SOURCES + platform/unix/qtx11extras.cpp platform/unix/qtx11extras_p.h +) + +qt_internal_extend_target(Gui CONDITION TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT UIKIT) + LIBRARIES + Qt::DBus +) + +qt_internal_extend_target(Gui CONDITION UNIX AND QT_FEATURE_settings AND QT_FEATURE_dbus AND (QT_FEATURE_xcb OR QT_FEATURE_wayland) + SOURCES + platform/unix/qkdetheme_p.h platform/unix/qkdetheme.cpp +) + +qt_internal_extend_target(Gui CONDITION UNIX AND (((QT_FEATURE_xcb OR NOT MACOS) AND (QT_FEATURE_xcb OR NOT UIKIT)) OR QT_FEATURE_wayland) + SOURCES + platform/unix/qgenericunixtheme.cpp platform/unix/qgenericunixtheme_p.h + platform/unix/qgnometheme_p.h platform/unix/qgnometheme.cpp +) + +qt_internal_extend_target(Gui CONDITION TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT MACOS) AND (QT_FEATURE_xcb OR NOT UIKIT) + SOURCES + platform/unix/dbusmenu/qdbusmenuadaptor.cpp platform/unix/dbusmenu/qdbusmenuadaptor_p.h + platform/unix/dbusmenu/qdbusmenubar.cpp platform/unix/dbusmenu/qdbusmenubar_p.h + platform/unix/dbusmenu/qdbusmenuconnection.cpp platform/unix/dbusmenu/qdbusmenuconnection_p.h + platform/unix/dbusmenu/qdbusmenuregistrarproxy.cpp platform/unix/dbusmenu/qdbusmenuregistrarproxy_p.h + platform/unix/dbusmenu/qdbusmenutypes.cpp platform/unix/dbusmenu/qdbusmenutypes_p.h + platform/unix/dbusmenu/qdbusplatformmenu.cpp platform/unix/dbusmenu/qdbusplatformmenu_p.h + platform/unix/qdbuslistener_p.h platform/unix/qdbuslistener.cpp + platform/unix/qdbussettings_p.h platform/unix/qdbussettings.cpp + platform/unix/qgnomeportalinterface.cpp platform/unix/qgnomeportalinterface_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_systemtrayicon AND TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT MACOS) AND (QT_FEATURE_xcb OR NOT UIKIT) + SOURCES + platform/unix/dbustray/qdbustrayicon.cpp platform/unix/dbustray/qdbustrayicon_p.h + platform/unix/dbustray/qdbustraytypes.cpp platform/unix/dbustray/qdbustraytypes_p.h + platform/unix/dbustray/qstatusnotifieritemadaptor.cpp platform/unix/dbustray/qstatusnotifieritemadaptor_p.h + platform/unix/dbustray/qxdgnotificationproxy.cpp platform/unix/dbustray/qxdgnotificationproxy_p.h +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_xkbcommon AND UNIX + SOURCES + platform/unix/qxkbcommon.cpp platform/unix/qxkbcommon_p.h + platform/unix/qxkbcommon_3rdparty.cpp + LIBRARIES + XKB::XKB + PRIVATE_MODULE_INTERFACE + XKB::XKB +) + +qt_internal_extend_target(Gui CONDITION QT_FEATURE_metal + SOURCES + rhi/qrhimetal.mm rhi/qrhimetal_p.h + PUBLIC_LIBRARIES + ${FWMetal} +) + +qt_internal_extend_target(Gui + SOURCES + painting/qdrawhelper.cpp painting/qdrawhelper_neon_p.h + NO_PCH_SOURCES + "painting/qdrawhelper.cpp" +) + +qt_internal_extend_target(Gui CONDITION (QT_FEATURE_eglfs OR QT_FEATURE_xcb OR QT_FEATURE_direct2d OR WIN32) + SOURCES + util/qedidparser.cpp util/qedidparser_p.h + util/qedidvendortable_p.h +) + +qt_internal_generate_tracepoints(Gui gui + SOURCES + image/qimage.cpp image/qimagereader.cpp image/qpixmap.cpp kernel/qguiapplication.cpp + text/qfontdatabase.cpp +) +qt_internal_add_docs(Gui + doc/qtgui.qdocconf +) + +if(IOS) + qt_internal_set_apple_privacy_manifest(Gui + "${CMAKE_CURRENT_SOURCE_DIR}/platform/ios/PrivacyInfo.xcprivacy") +endif() + +qt_internal_add_optimize_full_flags() + +if(QT_FEATURE_doc_snippets) + add_subdirectory(doc/snippets) +endif() diff --git a/local/recipes/qt/qtbase/source/src/gui/accessible/qaccessible.cpp b/local/recipes/qt/qtbase/source/src/gui/accessible/qaccessible.cpp index 30ebe90da0..f735507651 100644 --- a/local/recipes/qt/qtbase/source/src/gui/accessible/qaccessible.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/accessible/qaccessible.cpp @@ -472,7 +472,8 @@ Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); With \a QAccessible::AnouncementPoliteness::Polite, assistive technologies should announce the message at the next graceful opportunity such as at the - end of speaking the current sentence or when the user pauses typing. + end of speaking the current sentence or when the user pauses typing. A + polite announcement might still interrupt an ongoing polite announcement. When specifying \a QAccessible::AnouncementPoliteness::Assertive, assistive technologies should notify the user immediately. diff --git a/local/recipes/qt/qtbase/source/src/gui/configure.cmake b/local/recipes/qt/qtbase/source/src/gui/configure.cmake index e34f4d8b30..db35764134 100644 --- a/local/recipes/qt/qtbase/source/src/gui/configure.cmake +++ b/local/recipes/qt/qtbase/source/src/gui/configure.cmake @@ -1334,7 +1334,7 @@ qt_feature("clipboard" PUBLIC SECTION "Kernel" LABEL "QClipboard" PURPOSE "Provides cut and paste operations." - CONDITION NOT INTEGRITY AND NOT QNX AND NOT rtems + CONDITION NOT INTEGRITY AND NOT rtems ) qt_feature_definition("clipboard" "QT_NO_CLIPBOARD" NEGATE VALUE "1") qt_feature("wheelevent" PUBLIC diff --git a/local/recipes/qt/qtbase/source/src/gui/doc/snippets/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/gui/doc/snippets/CMakeLists.txt index e314d577d2..ef39eafbac 100644 --- a/local/recipes/qt/qtbase/source/src/gui/doc/snippets/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/gui/doc/snippets/CMakeLists.txt @@ -6,7 +6,6 @@ qt_add_library(gui_snippets OBJECT brush/gradientcreationsnippet.cpp image/image.cpp image/supportedformat.cpp - picture/picture.cpp polygon/polygon.cpp qimagewriter/main.cpp qtextobject/textobjectinterface.h @@ -20,6 +19,13 @@ target_link_libraries(gui_snippets PRIVATE Qt::GuiPrivate ) + +if(QT_FEATURE_picture) + target_sources(gui_snippets PRIVATE + picture/picture.cpp + ) +endif() + if(QT_FEATURE_widgets) target_link_libraries(gui_snippets PRIVATE Qt::Widgets diff --git a/local/recipes/qt/qtbase/source/src/gui/doc/snippets/code/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/gui/doc/snippets/code/CMakeLists.txt index 5589bb69b6..384cc650dd 100644 --- a/local/recipes/qt/qtbase/source/src/gui/doc/snippets/code/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/gui/doc/snippets/code/CMakeLists.txt @@ -8,7 +8,6 @@ add_library(gui_snippets_code OBJECT src_gui_image_qimagewriter.cpp src_gui_image_qpixmap.cpp src_gui_image_qpixmapcache.cpp - src_gui_kernel_qevent.cpp src_gui_kernel_qguiapplication_x11.cpp src_gui_kernel_qshortcut.cpp src_gui_kernel_qshortcutmap.cpp @@ -36,6 +35,12 @@ target_link_libraries(gui_snippets_code PRIVATE Qt::Gui ) +if(QT_FEATURE_wheelevent) + target_sources(gui_snippets_code PRIVATE + src_gui_kernel_qevent.cpp + ) +endif() + if(QT_FEATURE_widgets) target_link_libraries(gui_snippets_code PRIVATE Qt::Widgets diff --git a/local/recipes/qt/qtbase/source/src/gui/itemmodels/qfilesystemmodel.cpp b/local/recipes/qt/qtbase/source/src/gui/itemmodels/qfilesystemmodel.cpp index 2b151543c7..1042bb1160 100644 --- a/local/recipes/qt/qtbase/source/src/gui/itemmodels/qfilesystemmodel.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/itemmodels/qfilesystemmodel.cpp @@ -415,7 +415,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS for (int i = 0; i < pathElements.size(); ++i) { QString element = pathElements.at(i); - if (i != 0) + if (i != 0 && !elementPath.endsWith(separator)) elementPath.append(separator); elementPath.append(element); if (i == pathElements.size() - 1) diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qguiapplication.cpp b/local/recipes/qt/qtbase/source/src/gui/kernel/qguiapplication.cpp index f955803b4f..718772f0fe 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qguiapplication.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qguiapplication.cpp @@ -2797,14 +2797,23 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf if (!window) return; - if (window->screen() == wse->screen.data()) + QScreen *screen = wse->screen.data(); + if (window->screen() == screen) return; - if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) { - if (QScreen *screen = wse->screen.data()) + auto *windowPrivate = QWindowPrivate::get(window); + QWindow *topLevelWindow = windowPrivate->topLevelWindow(QWindow::ExcludeTransients); + if (window == topLevelWindow) { + if (screen) topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */); else // Fall back to default behavior, and try to find some appropriate screen topLevelWindow->setScreen(nullptr); + } else if (screen) { + // Child windows reflect the screen of their top level parent. When a + // window is reparented into a window that lives on a different screen + // we don't need to update the top level screen, but do need to emit + // screen changes for the child and its children, + windowPrivate->emitScreenChangedRecursion(screen); } } diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qinputdevice.cpp b/local/recipes/qt/qtbase/source/src/gui/kernel/qinputdevice.cpp index caed0fc613..0560c98632 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qinputdevice.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qinputdevice.cpp @@ -264,7 +264,7 @@ Q_CONSTINIT static QBasicMutex devicesMutex; Returns a list of all registered input devices (keyboards and pointing devices). \note The list of devices is not always complete on all platforms. So far, - the most-complete information is available on the \l {Qt for Linux/X11}{X11} + the most-complete information is available on the \l {Qt for Linux}{Linux} platform, at startup and in response to hot-plugging. Most other platforms are only able to provide generic devices of various types, only after receiving events from them; and most platforms do not tell Qt when a device is plugged in, diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qoffscreensurface_p.h b/local/recipes/qt/qtbase/source/src/gui/kernel/qoffscreensurface_p.h index 3de4b5e17a..8b9e0cf9c8 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qoffscreensurface_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qoffscreensurface_p.h @@ -15,7 +15,7 @@ // We mean it. // -#include "qplatformoffscreensurface.h" +#include #include diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qopenglcontext.cpp b/local/recipes/qt/qtbase/source/src/gui/kernel/qopenglcontext.cpp index d49886087c..c50ec76c82 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qopenglcontext.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qopenglcontext.cpp @@ -804,9 +804,18 @@ void QOpenGLContext::swapBuffers(QSurface *surface) } /*! - Resolves the function pointer to an OpenGL extension function, identified by \a procName + Resolves the function pointer to an OpenGL extension function, identified by \a procName. - Returns \nullptr if no such function can be found. + Use this function to access OpenGL extension functions or core functions + that may not be available as linked symbols on all platforms. + + The returned pointer may be platform-dependent. Some systems may return a + pointer that is not \nullptr even if the function is not valid or supported. + + To reliably check function availability, test for extension support by calling + \l QOpenGLContext::hasExtension(). For core functions, check the current context's + version via \l{QSurfaceFormat::}{version()} in the QSurfaceFormat returned by + \l QOpenGLContext::format(). */ QFunctionPointer QOpenGLContext::getProcAddress(const QByteArray &procName) const { diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette.cpp b/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette.cpp index 70b0e066b1..ee6d55d27c 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette.cpp @@ -11,6 +11,9 @@ QT_BEGIN_NAMESPACE +Q_CONSTINIT QAtomicInt QPalettePrivate::qt_palette_count = Q_BASIC_ATOMIC_INITIALIZER(0); +Q_CONSTINIT QAtomicInt QPalettePrivate::qt_palette_private_count = Q_BASIC_ATOMIC_INITIALIZER(0); + static_assert(QPalettePrivate::bitPosition(QPalette::ColorGroup(QPalette::NColorGroups - 1), QPalette::ColorRole(QPalette::NColorRoles - 1)) < sizeof(QPalette::ResolveMask) * CHAR_BIT, diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette_p.h b/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette_p.h index ce7c30d66d..9c489281b1 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qpalette_p.h @@ -17,6 +17,8 @@ #include "qpalette.h" +#include + QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QPalettePrivate @@ -66,8 +68,8 @@ public: QAtomicInt ref; QPalette::ResolveMask resolveMask = {0}; - static inline int qt_palette_count = 0; - static inline int qt_palette_private_count = 0; + static QAtomicInt qt_palette_count; + static QAtomicInt qt_palette_private_count; int detach_no = ++qt_palette_private_count; QExplicitlySharedDataPointer data; }; diff --git a/local/recipes/qt/qtbase/source/src/gui/kernel/qwindow.cpp b/local/recipes/qt/qtbase/source/src/gui/kernel/qwindow.cpp index bad5932c45..84963f4994 100644 --- a/local/recipes/qt/qtbase/source/src/gui/kernel/qwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/kernel/qwindow.cpp @@ -793,9 +793,10 @@ void QWindow::setParent(QWindow *parent) if (d->parentWindow == parent) return; - QScreen *newScreen = parent ? parent->screen() : screen(); + QScreen *oldScreen = screen(); + QScreen *newScreen = parent ? parent->screen() : oldScreen; if (d->windowRecreationRequired(newScreen)) { - qWarning() << this << '(' << parent << "): Cannot change screens (" << screen() << newScreen << ')'; + qWarning() << this << '(' << parent << "): Cannot change screens (" << oldScreen << newScreen << ')'; return; } @@ -844,6 +845,15 @@ void QWindow::setParent(QWindow *parent) QAccessible::updateAccessibility(&qaEvent); } #endif + + // The QPA layer should detect screen changes for child windows, and emit + // QWSI::handleWindowScreenChanged, but due to the ordering above where the + // parentWindow member is updated before calling setParent on the platform + // window we'll end up treating those callbacks from the QPA layer as noops + // in processWindowScreenChangedEvent since the screen is already up to date. + // To work around this we emit an explicit update here. + if (parent && screen() != oldScreen) + d->emitScreenChangedRecursion(screen()); } /*! diff --git a/local/recipes/qt/qtbase/source/src/gui/opengl/qopenglprogrambinarycache.cpp b/local/recipes/qt/qtbase/source/src/gui/opengl/qopenglprogrambinarycache.cpp index 7e1120f2eb..d21a0c58a0 100644 --- a/local/recipes/qt/qtbase/source/src/gui/opengl/qopenglprogrambinarycache.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef Q_OS_UNIX #include @@ -298,7 +299,8 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId) p = static_cast(map.ptr) + BASE_HEADER_SIZE; #else buf = f.readAll(); - p = reinterpret_cast(buf.constData()); + // QTBUG-142080: QByteArray::constData() confuses GCC, do it differently + p = reinterpret_cast(q20::to_address(buf.cbegin())); #endif GLEnvInfo info; diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qbackingstoredefaultcompositor.cpp b/local/recipes/qt/qtbase/source/src/gui/painting/qbackingstoredefaultcompositor.cpp index fae9dabca6..3130a8aea9 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qbackingstoredefaultcompositor.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qbackingstoredefaultcompositor.cpp @@ -133,15 +133,19 @@ static inline QPoint scaledOffset(const QPoint &pt, qreal factor) return pt * factor; } -static QRegion scaledRegion(const QRegion ®ion, qreal factor, const QPoint &offset) +static QRegion scaledDirtyRegion(const QRegion ®ion, qreal factor, const QPoint &offset) { if (offset.isNull() && factor <= 1) return region; QVarLengthArray rects; rects.reserve(region.rectCount()); + // Add 1x1 to the size since this is specifically for dirty regions for + // toTexture(), so a slightly bigger size is not an issue in any case. This + // fixes not uploading the last line/column in with non-integer high dpi + // scale factors such as 1.25. for (const QRect &rect : region) - rects.append(scaledRect(rect.translated(offset), factor)); + rects.append(scaledRect(rect.translated(offset), factor).adjusted(0, 0, 1, 1)); QRegion deviceRegion; deviceRegion.setRects(rects.constData(), rects.size()); @@ -511,13 +515,14 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo QRhiResourceUpdateBatch *resourceUpdates = rhi->nextResourceUpdateBatch(); QPlatformBackingStore::TextureFlags flags; + const QRegion dirtyRegion = scaledDirtyRegion(region, sourceTransformFactor, offset); bool gotTextureFromGraphicsBuffer = false; if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) { if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) { const QImage::Format format = QImage::toImageFormat(graphicsBuffer->format()); const QSize size = graphicsBuffer->size(); QImage wrapperImage(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), format); - toTexture(wrapperImage, rhi, resourceUpdates, scaledRegion(region, sourceTransformFactor, offset), &flags); + toTexture(wrapperImage, rhi, resourceUpdates, dirtyRegion, &flags); gotTextureFromGraphicsBuffer = true; graphicsBuffer->unlock(); if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft) @@ -525,7 +530,7 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo } } if (!gotTextureFromGraphicsBuffer) - toTexture(backingStore, rhi, resourceUpdates, scaledRegion(region, sourceTransformFactor, offset), &flags); + toTexture(backingStore, rhi, resourceUpdates, dirtyRegion, &flags); ensureResources(resourceUpdates, swapchain->renderPassDescriptor()); diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qpaintengine_raster.cpp b/local/recipes/qt/qtbase/source/src/gui/painting/qpaintengine_raster.cpp index 8e81539484..f411b1e10a 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qpaintengine_raster.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qpaintengine_raster.cpp @@ -2808,7 +2808,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, qFloor(positions[i].x) + alphaMap->x, qFloor(y) - alphaMap->y, alphaMap->width, alphaMap->height, - fontEngine->expectsGammaCorrectedBlending()); + fontEngine->expectsGammaCorrectedBlending(QFontEngine::GlyphFormat(alphaMap->format))); } } else { @@ -2872,7 +2872,14 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format())); s->matrix = originalTransform; } else { - alphaPenBlt(glyphBits, bpl, depth, x, y, c.w, c.h, fontEngine->expectsGammaCorrectedBlending()); + alphaPenBlt(glyphBits, + bpl, + depth, + x, + y, + c.w, + c.h, + fontEngine->expectsGammaCorrectedBlending(glyphFormat)); } } } diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qpainterpath.cpp b/local/recipes/qt/qtbase/source/src/gui/painting/qpainterpath.cpp index 9c9bf8bb93..47d67a50ee 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qpainterpath.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qpainterpath.cpp @@ -85,7 +85,7 @@ void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, if (!points[i]) continue; - qreal theta = angles[i] - 360 * qFloor(angles[i] / 360); + qreal theta = angles[i] - 360 * std::floor(angles[i] / 360); qreal t = theta / 90; // truncate int quadrant = int(t); @@ -970,6 +970,13 @@ void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle) { + if (!hasValidCoords(rect) || !isValidCoord(angle)) { +#ifndef QT_NO_DEBUG + qWarning("QPainterPath::arcMoveTo: Adding point with invalid coordinates, ignoring call"); +#endif + return; + } + if (rect.isNull()) return; diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qrasterbackingstore.cpp b/local/recipes/qt/qtbase/source/src/gui/painting/qrasterbackingstore.cpp index 158f86d5e8..041071f325 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qrasterbackingstore.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qrasterbackingstore.cpp @@ -6,7 +6,6 @@ #include #include -#include #include QT_BEGIN_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.h b/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.h index 1cc6aabcbd..f827b37e17 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.h +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.h @@ -5,6 +5,8 @@ #define QRGBA64_H #include + +#include #include QT_BEGIN_NAMESPACE @@ -148,6 +150,9 @@ public: } private: + friend constexpr size_t qHash(QRgba64 key, size_t seed = 0) noexcept + { return QHashPrivate::ex1to2arg(key.rgba, seed); } + Q_ALWAYS_INLINE static constexpr quint64 alphaMask() { return Q_UINT64_C(0xffff) << AlphaShift; } Q_ALWAYS_INLINE static constexpr quint8 div_257_floor(uint x) { return quint8((x - (x >> 8)) >> 8); } diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.qdoc b/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.qdoc index fd78b539a3..4fd8507db1 100644 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.qdoc +++ b/local/recipes/qt/qtbase/source/src/gui/painting/qrgba64.qdoc @@ -277,3 +277,13 @@ \sa QRgba64::alpha8(), QColor::alpha() */ + +/*! + \fn size_t QRgba64::qHash(QRgba64 key, size_t seed = 0); + \qhash{QRgba64} + \since 6.11.1 + + In Qt versions prior to 6.11.1, the type was hashable via its implicit + conversion to quint64. This explicit qHash() overload retains compatibility + with that implicit qHash(). +*/ diff --git a/local/recipes/qt/qtbase/source/src/gui/painting/qt_float16_shims.c b/local/recipes/qt/qtbase/source/src/gui/painting/qt_float16_shims.c deleted file mode 100644 index ccac3ab6e8..0000000000 --- a/local/recipes/qt/qtbase/source/src/gui/painting/qt_float16_shims.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * IEEE 754 half-precision soft-float conversion shims for Redox OS - * - * These compiler runtime functions (__truncsfhf2, __extendhfsf2, etc.) are - * normally provided by libgcc or compiler-rt. The Redox cross-toolchain - * (x86_64-unknown-redox-gcc, GCC 13.2.0) does not include them because - * x86_64 has no native half-precision support (no AVX512FP16). - * - * Qt6's qfloat16.cpp triggers the compiler to emit calls to these functions. - * We provide them here so QtCore links successfully. - * - * Format: IEEE 754 binary16 (half): 1 sign + 5 exp (bias 15) + 10 mantissa - * IEEE 754 binary32 (float): 1 sign + 8 exp (bias 127) + 23 mantissa - * - * SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - */ - -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; - -/* --- float16 -> float32 --- */ -float __extendhfsf2(uint16_t h) -{ - uint32_t sign = (h >> 15) & 1; - uint32_t exp = (h >> 10) & 0x1f; - uint32_t frac = h & 0x3ff; - uint32_t bits; - - if (exp == 0) { - if (frac == 0) { - /* +/- zero */ - bits = sign << 31; - } else { - /* Denormalized half: normalize it */ - exp = 1; - while (!(frac & 0x400)) { - frac <<= 1; - exp--; - } - frac &= 0x3ff; - bits = (sign << 31) | ((exp + 127 - 15) << 23) | (frac << 13); - } - } else if (exp == 0x1f) { - /* Inf or NaN */ - bits = (sign << 31) | (0xffu << 23) | (frac << 13); - } else { - /* Normalized */ - bits = (sign << 31) | ((exp + 127 - 15) << 23) | (frac << 13); - } - - union { uint32_t i; float f; } u; - u.i = bits; - return u.f; -} - -/* --- float32 -> float16 --- */ -uint16_t __truncsfhf2(float f) -{ - union { uint32_t i; float f; } u; - u.f = f; - uint32_t bits = u.i; - - uint32_t sign = (bits >> 31) & 1; - int exp = ((bits >> 23) & 0xff) - 127; - uint32_t frac = bits & 0x7fffff; - - /* Handle zero / denormal float input */ - if (((bits >> 23) & 0xff) == 0) { - if (frac == 0) return (uint16_t)(sign << 15); - /* Normalize denormal float */ - while (!(frac & 0x400000)) { - frac <<= 1; - exp--; - } - frac &= 0x3fffff; - } - - exp += 15; /* rebias to half-precision */ - - if (exp <= 0) { - /* Underflow: return +/- zero */ - return (uint16_t)(sign << 15); - } - if (exp >= 0x1f) { - /* Overflow: return +/- inf */ - return (uint16_t)((sign << 15) | 0x7c00); - } - - /* Round to nearest even: add 0x1000 (half of the gap between half-prec - representable values at the LSB position in the 23-bit mantissa). */ - frac = (frac + 0x1000) >> 13; - - /* Mantissa overflow from rounding */ - if (frac & 0x400) { - frac = 0; - exp++; - if (exp >= 0x1f) - return (uint16_t)((sign << 15) | 0x7c00); - } - - return (uint16_t)((sign << 15) | (exp << 10) | frac); -} - -/* --- float16 -> float64 --- */ -double __extendhfdf2(uint16_t h) -{ - /* Go through float32 — float has more than enough precision for half */ - float f = __extendhfsf2(h); - return (double)f; -} - -/* --- float64 -> float16 --- */ -uint16_t __truncdfhf2(double d) -{ - /* Double -> float -> half: no meaningful precision loss for half output */ - return __truncsfhf2((float)d); -} - -/* --- long double -> float16 --- */ -uint16_t __truncxfhf2(long double ld) -{ - return __truncsfhf2((float)ld); -} - -/* --- half-precision comparisons --- */ -int __eqhf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa == fb; -} -int __nehf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa != fb; -} -int __lthf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa < fb ? -1 : (fa == fb ? 0 : 1); -} -int __lehf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa <= fb ? 0 : 1; -} -int __gthf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa > fb ? 1 : (fa == fb ? 0 : -1); -} -int __gehf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa >= fb ? 0 : -1; -} -int __unordhf2(uint16_t a, uint16_t b) -{ - float fa = __extendhfsf2(a); - float fb = __extendhfsf2(b); - return fa != fa || fb != fb; -} diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine.mm b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine.mm index 925135e962..ee73599a34 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine.mm +++ b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine.mm @@ -405,7 +405,7 @@ auto *configuredImage(const UIImage *image, const QColor &color) QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) { - const CacheKey key(mode, state, size, scale); + const CacheKey key(mode, state, QPalette(), size, scale); QPixmap pixmap = m_cache.value(key); if (pixmap.isNull()) { const QSize paintSize = actualSize(size, mode, state); diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine_p.h b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine_p.h index b71386ca63..2d60da71f2 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qappleiconengine_p.h @@ -16,6 +16,7 @@ // #include +#include #include @@ -57,17 +58,22 @@ private: const UIImage *m_image; #endif struct CacheKey { - constexpr CacheKey(QIcon::Mode mode, QIcon::State state, QSize size, qreal scale) noexcept - : modeAndState((quint64(mode) << 32) | state), size(size), scale(scale) + constexpr CacheKey(QIcon::Mode mode, QIcon::State state, const QPalette &palette, QSize size, qreal scale) noexcept + : modeAndState((quint64(mode) << 32) | state) + , paletteCacheKey(palette.cacheKey()) + , size(size) + , scale(scale) {} quint64 modeAndState; + quint64 paletteCacheKey; QSize size; qreal scale; friend constexpr bool operator==(const CacheKey &lhs, const CacheKey &rhs) noexcept { return lhs.modeAndState == rhs.modeAndState + && lhs.paletteCacheKey == rhs.paletteCacheKey && lhs.size == rhs.size && lhs.scale == rhs.scale; } diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper.mm b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper.mm index 49f7a8ff0c..f0fd48a46e 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper.mm +++ b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper.mm @@ -38,6 +38,19 @@ static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers m return swappedModifiers; } +[[maybe_unused]] static Qt::Key swapModifierIfNeeded(const Qt::Key key) +{ + if (QCoreApplication::testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) + return key; + + if (key == Qt::Key_Meta) + return Qt::Key_Control; + else if (key == Qt::Key_Control) + return Qt::Key_Meta; + + return key; +} + #ifdef Q_OS_MACOS static constexpr std::tuple cocoaModifierMap[] = { { NSEventModifierFlagShift, Qt::ShiftModifier }, @@ -669,6 +682,26 @@ API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode return Qt::Key_unknown; } +Qt::Key QAppleKeyMapper::fromUIKitKey(UIKeyboardHIDUsage usage) +{ + static QHash modifierKeys = { + { UIKeyboardHIDUsageKeyboardCapsLock, Qt::Key_CapsLock }, + { UIKeyboardHIDUsageKeyboardLeftAlt, Qt::Key_Alt }, + { UIKeyboardHIDUsageKeyboardRightAlt, Qt::Key_Alt }, + { UIKeyboardHIDUsageKeyboardLeftControl, Qt::Key_Control }, + { UIKeyboardHIDUsageKeyboardRightControl, Qt::Key_Control }, + { UIKeyboardHIDUsageKeyboardLeftShift, Qt::Key_Shift }, + { UIKeyboardHIDUsageKeyboardRightShift, Qt::Key_Shift }, + { UIKeyboardHIDUsageKeyboardLeftGUI, Qt::Key_Meta }, + { UIKeyboardHIDUsageKeyboardRightGUI, Qt::Key_Meta }, + }; + + if (auto key = modifierKeys.value(usage)) + return swapModifierIfNeeded(key); + + return Qt::Key_unknown; +} + static constexpr std::tuple uiKitModifierMap[] = { { UIKeyModifierShift, Qt::ShiftModifier }, { UIKeyModifierControl, Qt::ControlModifier }, diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper_p.h b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper_p.h index 1f3494d16f..e967f94b5a 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/platform/darwin/qapplekeymapper_p.h @@ -46,6 +46,7 @@ public: NSString *charactersIgnoringModifiers, QString &text); static Qt::Key fromUIKitKey(NSString *keyCode); + static Qt::Key fromUIKitKey(UIKeyboardHIDUsage usage); static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers); static ulong toUIKitModifiers(Qt::KeyboardModifiers); #endif diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon.cpp b/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon.cpp index 787c48c3c0..b298f831d1 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon.cpp @@ -81,6 +81,26 @@ static inline QString tempFileTemplate() return TempFileTemplate; } +QDBusArgument &operator<<(QDBusArgument &argument, const QDBusTrayImage &img) +{ + QImage image = img.ico.pixmap(QSize(64, 64), img.dpr).toImage(); + const bool hasAlpha = image.hasAlphaChannel(); + image = image.convertToFormat(hasAlpha ? QImage::Format_RGBA8888 : QImage::Format_RGB888); + + argument.beginStructure(); + argument << image.width() << image.height() + << image.bytesPerLine() << hasAlpha + << 8 << (hasAlpha ? 4 : 3) + << QByteArray((const char *)image.constBits(), image.sizeInBytes()); + argument.endStructure(); + return argument; +} +const QDBusArgument &operator>>(const QDBusArgument &argument, QDBusTrayImage &) +{ + Q_ASSERT_X(false, __FUNCTION__, "Not implemented"); + return argument; +} + /*! \class QDBusTrayIcon \internal @@ -318,6 +338,11 @@ void QDBusTrayIcon::showMessage(const QString &title, const QString &msg, const if (urgency < 0) // no icon urgency = 0; hints.insert("urgency"_L1, QVariant(urgency)); + if (m_attentionIconName.isEmpty()) { + qDBusRegisterMetaType(); + const QDBusTrayImage img = {icon, qGuiApp->devicePixelRatio()}; + hints.insert("image_data"_L1, QVariant::fromValue(img)); + } m_notifier->notify(QCoreApplication::applicationName(), 0, m_attentionIconName, title, msg, notificationActions, hints, msecs); } diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon_p.h b/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon_p.h index 7a09f9c181..15a83277f2 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/platform/unix/dbustray/qdbustrayicon_p.h @@ -127,6 +127,15 @@ private: bool m_registered; }; +struct QDBusTrayImage +{ + QIcon ico; + qreal dpr = 0; +}; + + QT_END_NAMESPACE +Q_DECLARE_METATYPE(QDBusTrayImage) + #endif // QDBUSTRAYICON_H diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/unix/qkdetheme.cpp b/local/recipes/qt/qtbase/source/src/gui/platform/unix/qkdetheme.cpp index f9c10023a0..f5d3e15769 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/unix/qkdetheme.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/platform/unix/qkdetheme.cpp @@ -67,6 +67,7 @@ public: ViewForegroundVisited, TooltipBackground, TooltipForeground, + ViewForegroundInactive, }; QKdeThemePrivate(const QStringList &kdeDirs, int kdeVersion); @@ -243,6 +244,7 @@ static constexpr QKdeThemePrivate::KdeSettingType settingsType(QKdeThemePrivate: CASE(ViewForegroundVisited, Colors); CASE(TooltipBackground, Colors); CASE(TooltipForeground, Colors); + CASE(ViewForegroundInactive, Colors); }; // GCC 8.x does not treat __builtin_unreachable() as constexpr # if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900) @@ -294,6 +296,8 @@ static constexpr QLatin1StringView settingsKey(QKdeThemePrivate::KdeSetting sett return QLatin1StringView("Window/BackgroundNormal"); case QKdeThemePrivate::KdeSetting::ViewForeground: return QLatin1StringView("View/ForegroundNormal"); + case QKdeThemePrivate::KdeSetting::ViewForegroundInactive: + return QLatin1StringView("View/ForegroundInactive"); case QKdeThemePrivate::KdeSetting::WindowForeground: return QLatin1StringView("Window/ForegroundNormal"); case QKdeThemePrivate::KdeSetting::ViewBackground: @@ -503,6 +507,7 @@ void QKdeThemePrivate::readKdeSystemPalette(const QStringList &kdeDirs, int kdeV kdeColor(pal, QPalette::LinkVisited, readKdeSetting(KdeSetting::ViewForegroundVisited, kdeDirs, kdeVersion, kdeSettings)); kdeColor(pal, QPalette::ToolTipBase, readKdeSetting(KdeSetting::TooltipBackground, kdeDirs, kdeVersion, kdeSettings)); kdeColor(pal, QPalette::ToolTipText, readKdeSetting(KdeSetting::TooltipForeground, kdeDirs, kdeVersion, kdeSettings)); + kdeColor(pal, QPalette::PlaceholderText, readKdeSetting(KdeSetting::ViewForegroundInactive, kdeDirs, kdeVersion, kdeSettings)); // The above code sets _all_ color roles to "normal" colors. In KDE, the disabled // color roles are calculated by applying various effects described in kdeglobals. diff --git a/local/recipes/qt/qtbase/source/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/local/recipes/qt/qtbase/source/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 8d06821d4c..3fa5d1bce0 100644 --- a/local/recipes/qt/qtbase/source/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -35,10 +35,12 @@ void showOpenViaHTMLPolyfill(const QStringList &accept, FileSelectMode fileSelec Q_UNUSED(accept); input.set("multiple", emscripten::val(fileSelectMode == FileSelectMode::MultipleFiles)); - // Note: there is no event in case the user cancels the file dialog. static std::unique_ptr changeEvent; + static std::unique_ptr cancelEvent; auto callback = [=](emscripten::val) { onFilesSelected.thenFunc(input["files"]); }; + auto cancelCallback = [=](emscripten::val) { onFilesSelected.catchFunc(emscripten::val::undefined()); }; changeEvent = std::make_unique(input, "change", callback); + cancelEvent = std::make_unique(input, "cancel", cancelCallback); // Activate file input emscripten::val body = document["body"]; diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qdxgivsyncservice.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qdxgivsyncservice.cpp index 5f9b39f803..c205f31a6e 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qdxgivsyncservice.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qdxgivsyncservice.cpp @@ -377,6 +377,12 @@ void QDxgiVSyncService::registerWindow(QWindow *window) if (disableService || windows.contains(window)) return; + if (window->format().swapInterval() == 0) { + qCDebug(lcQpaScreenUpdates) << "QDxgiVSyncService: window" << window + << "has swapInterval 0, skipping this window"; + return; + } + qCDebug(lcQpaScreenUpdates) << "QDxgiVSyncService: adding window" << window; WindowData wd; diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi.cpp index de451e243e..872b55f9e3 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi.cpp @@ -8815,6 +8815,24 @@ bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBin return true; } +bool QRhiImplementation::sanityCheckResourceOwnership(QRhiResource *maybeResource) +{ + if (maybeResource == nullptr || maybeResource->m_rhi == nullptr) + return true; + + if (maybeResource->m_rhi->q != q) { + qWarning("%s %p (%s) belongs to QRhi %p, but client code attempted to use it with QRhi %p. This is wrong.", + resourceTypeStr(maybeResource), + maybeResource, + maybeResource->m_objectName.constData(), + maybeResource->m_rhi->q, + q); + return false; + } + + return true; +} + int QRhiImplementation::effectiveSampleCount(int sampleCount) const { // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1. @@ -10171,6 +10189,13 @@ void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates) between a beginPass() and endPass() call. \note The new graphics pipeline \a ps must be a valid pointer. + + Setting a graphics pipeline that does not have the + \l{QRhiGraphicsPipeline::}{UsesScissor} flag will either disable scissoring, + with graphics APIs where that is applicable, or set the scissor rectangle to + match the viewport that was last set (with graphics APIs where scissoring is + effectively always active), in order to ensure a uniform behavior across QRhi + backends. */ void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps) { diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi_p.h b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi_p.h index a7c113be71..d7323584e4 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhi_p.h @@ -200,6 +200,7 @@ public: bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps); bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb); + bool sanityCheckResourceOwnership(QRhiResource *maybeResource); void updateLayoutDesc(QRhiShaderResourceBindings *srb); quint32 pipelineCacheRhiId() const @@ -621,7 +622,7 @@ struct QRhiBatchedBindings struct Batch { uint startBinding; - QVarLengthArray resources; + QVector resources; bool operator==(const Batch &other) const { @@ -634,7 +635,10 @@ struct QRhiBatchedBindings } }; - QVarLengthArray batches; // sorted by startBinding + // some backends make copies of QRhiBatchedBindings -> implicit sharing and + // not having a (possibly wasted) prealloc are beneficial -> use QVector + // instead of QVLA + QVector batches; // sorted by startBinding bool operator==(const QRhiBatchedBindings &other) const { diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d11.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d11.cpp index 73448a4c24..e6a567a64c 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d11.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d11.cpp @@ -1069,6 +1069,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf); // NonDynamicUniformBuffers is not supported by this backend Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic && bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); + sanityCheckResourceOwnership(bufD); executeBufferHostWrites(bufD); @@ -1095,6 +1096,8 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind // images and samplers, so tex or sampler (but not both) can be // null here. Q_ASSERT(texD || samplerD); + sanityCheckResourceOwnership(texD); + sanityCheckResourceOwnership(samplerD); const quint64 texId = texD ? texD->m_id : 0; const uint texGen = texD ? texD->generation : 0; const quint64 samplerId = samplerD ? samplerD->m_id : 0; @@ -1118,6 +1121,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::ImageLoadStore: { QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex); + sanityCheckResourceOwnership(texD); if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) { srbUpdate = true; bd.simage.id = texD->m_id; @@ -1130,6 +1134,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::BufferLoadStore: { QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf); + sanityCheckResourceOwnership(bufD); if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) { srbUpdate = true; bd.sbuf.id = bufD->m_id; @@ -5459,7 +5464,11 @@ bool QD3D11SwapChain::createOrResize() rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES); } } - if (FAILED(hr)) { + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) { + qWarning("Device loss detected during swapchain creation"); + rhiD->deviceLost = true; + return false; + } else if (FAILED(hr)) { qWarning("Failed to create D3D11 swapchain: %s" " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)", qPrintable(QSystemError::windowsComString(hr)), diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12.cpp index b2bf6091d3..beec140645 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12.cpp @@ -1042,6 +1042,9 @@ void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline if (psD->viewInstanceMask) cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask); + + if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) + setDefaultScissor(cbD); } } @@ -1166,6 +1169,7 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.ubuf.buf); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic); + sanityCheckResourceOwnership(bufD); bufD->executeHostWritesForFrameSlot(currentFrameSlot); } break; @@ -1181,6 +1185,8 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind // images and samplers, so tex or sampler (but not both) can be // null here. Q_ASSERT(texD || samplerD); + sanityCheckResourceOwnership(texD); + sanityCheckResourceOwnership(samplerD); if (texD) { UINT state = 0; if (b->stage == QRhiShaderResourceBinding::FragmentStage) { @@ -1201,6 +1207,7 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::ImageLoadStore: { QD3D12Texture *texD = QRHI_RES(QD3D12Texture, b->u.simage.tex); + sanityCheckResourceOwnership(texD); if (QD3D12Resource *res = resourcePool.lookupRef(texD->handle)) { if (res->uavUsage) { if (res->uavUsage & QD3D12Resource::UavUsageWrite) { @@ -1230,6 +1237,7 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::BufferLoadStore: { QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, b->u.sbuf.buf); + sanityCheckResourceOwnership(bufD); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic); if (QD3D12Resource *res = resourcePool.lookupRef(bufD->handles[0])) { @@ -1479,6 +1487,33 @@ void QRhiD3D12::setVertexInput(QRhiCommandBuffer *cb, } } +void QRhiD3D12::setDefaultScissor(QD3D12CommandBuffer *cbD) +{ + cbD->hasCustomScissorSet = false; + + const QSize outputSize = cbD->currentTarget->pixelSize(); + std::array vp = cbD->currentViewport.viewport(); + float x = 0, y = 0, w = 0, h = 0; + + if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) { + x = 0; + y = 0; + w = outputSize.width(); + h = outputSize.height(); + } else { + // x,y is top-left in D3D12_RECT but bottom-left in QRhiScissor + qrhi_toTopLeftRenderTargetRect(outputSize, vp, &x, &y, &w, &h); + } + + D3D12_RECT r; + r.left = x; + r.top = y; + // right and bottom are exclusive + r.right = x + w; + r.bottom = y + h; + cbD->cmdList->RSSetScissorRects(1, &r); +} + void QRhiD3D12::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) { QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb); @@ -1500,17 +1535,11 @@ void QRhiD3D12::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) v.MaxDepth = viewport.maxDepth(); cbD->cmdList->RSSetViewports(1, &v); + cbD->currentViewport = viewport; if (cbD->currentGraphicsPipeline - && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor)) + && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor)) { - qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h); - D3D12_RECT r; - r.left = x; - r.top = y; - // right and bottom are exclusive - r.right = x + w; - r.bottom = y + h; - cbD->cmdList->RSSetScissorRects(1, &r); + setDefaultScissor(cbD); } } @@ -1533,6 +1562,8 @@ void QRhiD3D12::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) r.right = x + w; r.bottom = y + h; cbD->cmdList->RSSetScissorRects(1, &r); + + cbD->hasCustomScissorSet = true; } void QRhiD3D12::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) @@ -6938,7 +6969,11 @@ bool QD3D12SwapChain::createOrResize() rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES); } } - if (FAILED(hr)) { + if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) { + qWarning("Device loss detected during swapchain creation"); + rhiD->deviceLost = true; + return false; + } else if (FAILED(hr)) { qWarning("Failed to create D3D12 swapchain: %s" " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)", qPrintable(QSystemError::windowsComString(hr)), diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12_p.h b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12_p.h index c9db71a8a5..0f0423855d 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhid3d12_p.h @@ -985,6 +985,8 @@ struct QD3D12CommandBuffer : public QRhiCommandBuffer currentVertexOffsets = {}; hasShadingRateSet = false; hasShadingRateMapSet = false; + hasCustomScissorSet = false; + currentViewport = {}; } // per-frame @@ -1005,6 +1007,8 @@ struct QD3D12CommandBuffer : public QRhiCommandBuffer std::array currentVertexOffsets; bool hasShadingRateSet; bool hasShadingRateMapSet; + bool hasCustomScissorSet; + QRhiViewport currentViewport; // global double lastGpuTime = 0; @@ -1250,6 +1254,7 @@ public: quint32 neededDescriptorCount, bool *gotNew); void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD); + void setDefaultScissor(QD3D12CommandBuffer *cbD); bool debugLayer = false; UINT maxFrameLatency = 2; // 1-3, use 2 to keep CPU-GPU parallelism while reducing lag compared to tripple buffering diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhigles2.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhigles2.cpp index 5208bd4d4b..c7a86e8b75 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhigles2.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhigles2.cpp @@ -780,10 +780,16 @@ bool QRhiGles2::create(QRhi::Flags flags) ctx->setFormat(requestedFormat); if (maybeShareContext) { ctx->setShareContext(maybeShareContext); - ctx->setScreen(maybeShareContext->screen()); + if (maybeWindow) + ctx->setScreen(maybeWindow->screen()); + else + ctx->setScreen(maybeShareContext->screen()); } else if (QOpenGLContext *shareContext = QOpenGLContext::globalShareContext()) { ctx->setShareContext(shareContext); - ctx->setScreen(shareContext->screen()); + if (maybeWindow) + ctx->setScreen(maybeWindow->screen()); + else + ctx->setScreen(shareContext->screen()); } else if (maybeWindow) { ctx->setScreen(maybeWindow->screen()); } @@ -1971,8 +1977,10 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::SampledTexture: case QRhiShaderResourceBinding::Texture: for (int elem = 0; elem < b->u.stex.count; ++elem) { + QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex); + sanityCheckResourceOwnership(texD); trackedRegisterTexture(&passResTracker, - QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex), + texD, QRhiPassResourceTracker::TexSample, QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage)); } @@ -1982,6 +1990,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::ImageLoadStore: { QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.simage.tex); + sanityCheckResourceOwnership(texD); QRhiPassResourceTracker::TextureAccess access; if (b->type == QRhiShaderResourceBinding::ImageLoad) access = QRhiPassResourceTracker::TexStorageLoad; @@ -1998,6 +2007,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::BufferLoadStore: { QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf); + sanityCheckResourceOwnership(bufD); QRhiPassResourceTracker::BufferAccess access; if (b->type == QRhiShaderResourceBinding::BufferLoad) access = QRhiPassResourceTracker::BufStorageLoad; diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal.mm b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal.mm index 46b8693514..31eeb285f2 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal.mm +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal.mm @@ -1528,6 +1528,9 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline cbD->currentComputePipeline = nullptr; cbD->currentPipelineGeneration = psD->generation; + if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) + setDefaultScissor(cbD); + if (!psD->d->tess.enabled && !psD->d->tess.failed) psD->makeActiveForCurrentRenderPassEncoder(cbD); @@ -1590,6 +1593,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind { QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); + sanityCheckResourceOwnership(bufD); executeBufferHostWritesForCurrentFrame(bufD); if (bufD->d->slotted) hasSlottedResourceInSrb = true; @@ -1616,6 +1620,8 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler); Q_ASSERT(texD || samplerD); + sanityCheckResourceOwnership(texD); + sanityCheckResourceOwnership(samplerD); const quint64 texId = texD ? texD->m_id : 0; const uint texGen = texD ? texD->generation : 0; const quint64 samplerId = samplerD ? samplerD->m_id : 0; @@ -1643,6 +1649,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind case QRhiShaderResourceBinding::ImageLoadStore: { QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex); + sanityCheckResourceOwnership(texD); if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) { resNeedsRebind = true; bd.simage.id = texD->m_id; @@ -1657,6 +1664,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind { QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); + sanityCheckResourceOwnership(bufD); if (needsBufferSizeBuffer) { for (int i = 0; i < 6; ++i) { @@ -1886,6 +1894,32 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb, } } +void QRhiMetal::setDefaultScissor(QMetalCommandBuffer *cbD) +{ + cbD->hasCustomScissorSet = false; + + const QSize outputSize = cbD->currentTarget->pixelSize(); + std::array vp = cbD->currentViewport.viewport(); + float x = 0, y = 0, w = 0, h = 0; + + if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) { + x = 0; + y = 0; + w = outputSize.width(); + h = outputSize.height(); + } else { + // x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor + qrhi_toTopLeftRenderTargetRect(outputSize, vp, &x, &y, &w, &h); + } + + MTLScissorRect s; + s.x = NSUInteger(x); + s.y = NSUInteger(y); + s.width = NSUInteger(w); + s.height = NSUInteger(h); + [cbD->d->currentRenderPassEncoder setScissorRect: s]; +} + void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) { QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb); @@ -1921,15 +1955,11 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) [cbD->d->currentRenderPassEncoder setViewport: vp]; + cbD->currentViewport = viewport; if (cbD->currentGraphicsPipeline - && !cbD->currentGraphicsPipeline->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) { - MTLScissorRect s; - qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h); - s.x = NSUInteger(x); - s.y = NSUInteger(y); - s.width = NSUInteger(w); - s.height = NSUInteger(h); - [cbD->d->currentRenderPassEncoder setScissorRect: s]; + && !cbD->currentGraphicsPipeline->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) + { + setDefaultScissor(cbD); } } @@ -1953,6 +1983,8 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) s.height = NSUInteger(h); [cbD->d->currentRenderPassEncoder setScissorRect: s]; + + cbD->hasCustomScissorSet = true; } void QRhiMetal::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) @@ -6275,6 +6307,8 @@ void QMetalCommandBuffer::resetPerPassCachedState() currentDepthClipMode = -1; currentFrontFaceWinding = -1; currentDepthBiasValues = { 0.0f, 0.0f }; + hasCustomScissorSet = false; + currentViewport = {}; d->currentShaderResourceBindingState = {}; d->currentDepthStencilState = nil; diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal_p.h b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal_p.h index c12e2106cf..c8b707a486 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhimetal_p.h @@ -302,6 +302,8 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer int currentDepthClipMode; int currentFrontFaceWinding; std::pair currentDepthBiasValues; + bool hasCustomScissorSet; + QRhiViewport currentViewport; const QRhiNativeHandles *nativeHandles(); void resetState(double lastGpuTime = 0); @@ -481,6 +483,8 @@ public: const QRhiCommandBuffer::DynamicOffset *dynamicOffsets, bool offsetOnlyChange, const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]); + void setDefaultScissor(QMetalCommandBuffer *cbD); + struct TessDrawArgs { QMetalCommandBuffer *cbD; enum { diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan.cpp b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan.cpp index 6d095fe9a2..0a20fe3395 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan.cpp @@ -3496,7 +3496,7 @@ inline void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource * } auto it = writtenResources->find(resource); if (it != writtenResources->end()) - it->first |= access; + it->second.accessFlags |= access; else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal) writtenResources->insert(resource, { access, true }); } @@ -3514,13 +3514,12 @@ void QRhiVulkan::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) // The key in the writtenResources map indicates that the resource was // written in a previous dispatch, whereas the value accumulates the // access mask in the current one. - for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources) - accessAndIsNewFlag = { 0, false }; + for (auto [res, accessAndIsNewFlag] : cbD->computePassState.writtenResources) + accessAndIsNewFlag = { 0, false }; // note: accessAndIsNewFlag is a reference QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, cbD->currentComputeSrb); - const int bindingCount = srbD->m_bindings.size(); - for (int i = 0; i < bindingCount; ++i) { - const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings.at(i)); + for (auto &binding : srbD->m_bindings) { + const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(binding); switch (b->type) { case QRhiShaderResourceBinding::ImageLoad: case QRhiShaderResourceBinding::ImageStore: @@ -3548,8 +3547,8 @@ void QRhiVulkan::dispatch(QRhiCommandBuffer *cb, int x, int y, int z) } for (auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) { - const int accessInThisDispatch = it->first; - const bool isNewInThisDispatch = it->second; + const VkAccessFlags accessInThisDispatch = it->second.accessFlags; + const bool isNewInThisDispatch = it->second.isNew; if (accessInThisDispatch && !isNewInThisDispatch) { if (it.key()->resourceType() == QRhiResource::Texture) { QVkTexture *texD = QRHI_RES(QVkTexture, it.key()); @@ -5717,6 +5716,9 @@ void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline cbD->currentGraphicsPipeline = ps; cbD->currentComputePipeline = nullptr; cbD->currentPipelineGeneration = psD->generation; + + if (cbD->hasCustomScissorSet && !psD->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) + setDefaultScissor(cbD); } psD->lastActiveFrameSlot = currentFrameSlot; @@ -5756,6 +5758,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin { QVkBuffer *bufD = QRHI_RES(QVkBuffer, b->u.ubuf.buf); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)); + sanityCheckResourceOwnership(bufD); if (bufD->m_type == QRhiBuffer::Dynamic) executeBufferHostWritesForSlot(bufD, currentFrameSlot); @@ -5792,6 +5795,8 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin // images and samplers, so tex or sampler (but not both) can be // null here. Q_ASSERT(texD || samplerD); + sanityCheckResourceOwnership(texD); + sanityCheckResourceOwnership(samplerD); if (texD) { texD->lastActiveFrameSlot = currentFrameSlot; trackedRegisterTexture(&passResTracker, texD, @@ -5823,6 +5828,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin case QRhiShaderResourceBinding::ImageLoadStore: { QVkTexture *texD = QRHI_RES(QVkTexture, b->u.simage.tex); + sanityCheckResourceOwnership(texD); Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedWithLoadStore)); texD->lastActiveFrameSlot = currentFrameSlot; QRhiPassResourceTracker::TextureAccess access; @@ -5862,6 +5868,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin { QVkBuffer *bufD = QRHI_RES(QVkBuffer, b->u.sbuf.buf); Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer)); + sanityCheckResourceOwnership(bufD); if (bufD->m_type == QRhiBuffer::Dynamic) executeBufferHostWritesForSlot(bufD, currentFrameSlot); @@ -6083,6 +6090,39 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb, } } +void QRhiVulkan::setDefaultScissor(QVkCommandBuffer *cbD) +{ + cbD->hasCustomScissorSet = false; + + const QSize outputSize = cbD->currentTarget->pixelSize(); + std::array vp = cbD->currentViewport.viewport(); + float x = 0, y = 0, w = 0, h = 0; + + if (qFuzzyIsNull(vp[2]) && qFuzzyIsNull(vp[3])) { + x = 0; + y = 0; + w = outputSize.width(); + h = outputSize.height(); + } else { + // x,y is top-left in VkRect2D but bottom-left in QRhiScissor + qrhi_toTopLeftRenderTargetRect(outputSize, vp, &x, &y, &w, &h); + } + + QVkCommandBuffer::Command &cmd(cbD->commands.get()); + VkRect2D *s = &cmd.args.setScissor.scissor; + s->offset.x = int32_t(x); + s->offset.y = int32_t(y); + s->extent.width = uint32_t(w); + s->extent.height = uint32_t(h); + + if (cbD->passUsesSecondaryCb) { + df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s); + cbD->commands.unget(); + } else { + cmd.cmd = QVkCommandBuffer::Command::SetScissor; + } +} + void QRhiVulkan::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) { QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb); @@ -6110,22 +6150,11 @@ void QRhiVulkan::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport cmd.cmd = QVkCommandBuffer::Command::SetViewport; } + cbD->currentViewport = viewport; if (cbD->currentGraphicsPipeline - && !QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) + && !cbD->currentGraphicsPipeline->flags().testFlag(QRhiGraphicsPipeline::UsesScissor)) { - QVkCommandBuffer::Command &cmd(cbD->commands.get()); - VkRect2D *s = &cmd.args.setScissor.scissor; - qrhi_toTopLeftRenderTargetRect(outputSize, viewport.viewport(), &x, &y, &w, &h); - s->offset.x = int32_t(x); - s->offset.y = int32_t(y); - s->extent.width = uint32_t(w); - s->extent.height = uint32_t(h); - if (cbD->passUsesSecondaryCb) { - df->vkCmdSetScissor(cbD->activeSecondaryCbStack.last(), 0, 1, s); - cbD->commands.unget(); - } else { - cmd.cmd = QVkCommandBuffer::Command::SetScissor; - } + setDefaultScissor(cbD); } } @@ -6156,6 +6185,8 @@ void QRhiVulkan::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) } else { cmd.cmd = QVkCommandBuffer::Command::SetScissor; } + + cbD->hasCustomScissorSet = true; } void QRhiVulkan::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) @@ -8225,10 +8256,11 @@ bool QVkShaderResourceBindings::create() } } - QVarLengthArray vkbindings; + QVarLengthArray vkbindings; + vkbindings.reserve(sortedBindings.size()); for (const QRhiShaderResourceBinding &binding : std::as_const(sortedBindings)) { const QRhiShaderResourceBinding::Data *b = QRhiImplementation::shaderResourceBindingData(binding); - VkDescriptorSetLayoutBinding vkbinding = {}; + VkDescriptorSetLayoutBinding &vkbinding = vkbindings.emplace_back(); vkbinding.binding = uint32_t(b->binding); vkbinding.descriptorType = toVkDescriptorType(b); if (b->type == QRhiShaderResourceBinding::SampledTexture || b->type == QRhiShaderResourceBinding::Texture) @@ -8236,7 +8268,6 @@ bool QVkShaderResourceBindings::create() else vkbinding.descriptorCount = 1; vkbinding.stageFlags = toVkShaderStageFlags(b->stage); - vkbindings.append(vkbinding); } VkDescriptorSetLayoutCreateInfo layoutInfo = {}; @@ -8787,7 +8818,7 @@ static inline bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, cons return s.format == VK_FORMAT_R16G16B16A16_SFLOAT && s.colorSpace == VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT; case QRhiSwapChain::HDR10: - return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32) + return s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 && s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT; case QRhiSwapChain::HDRExtendedDisplayP3Linear: return s.format == VK_FORMAT_R16G16B16A16_SFLOAT @@ -8906,37 +8937,81 @@ bool QVkSwapChain::ensureSurface() quint32 formatCount = 0; rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, nullptr); QList formats(formatCount); - if (formatCount) - rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data()); + rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, + formats.data()); - // See if there is a better match than the default BGRA8 format. (but if - // not, we will stick to the default) + // Initially select the first available format, will only be used as a worst-case fallback + colorFormat = formats.constFirst().format; + colorSpace = formats.constFirst().colorSpace; + + // See if we can find the preferred SDR format const bool srgbRequested = m_flags.testFlag(sRGB); - for (int i = 0; i < int(formatCount); ++i) { - if (formats[i].format != VK_FORMAT_UNDEFINED) { - bool ok = srgbRequested == isSrgbFormat(formats[i].format); - if (m_format != SDR) - ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]); + bool foundBestFormat = false; + if (m_format == SDR) { + for (int i = 0; i < int(formatCount); ++i) { + bool ok; + if (srgbRequested) { + ok = defaultSrgbColorFormat == formats[i].format; + } else { + ok = defaultColorFormat == formats[i].format; + } if (ok) { + foundBestFormat = true; colorFormat = formats[i].format; colorSpace = formats[i].colorSpace; -#if QT_CONFIG(wayland) - // On Wayland, only one color management surface can be created at a time without - // triggering a protocol error, and we create one ourselves in some situations. - // To avoid this problem, use VK_COLOR_SPACE_PASS_THROUGH_EXT when supported, - // so that the driver doesn't create a color management surface as well. - const bool hasPassThrough = std::any_of(formats.begin(), formats.end(), [this](const VkSurfaceFormatKHR &fmt) { - return fmt.format == colorFormat && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT; - }); - if (hasPassThrough) { - colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT; - } -#endif break; } } } + // Otherwise pick one that fits our requirements: + if (!foundBestFormat && (m_format != SDR || srgbRequested)) { + for (int i = 0; i < int(formatCount); ++i) { + bool ok = false; + if (m_format != SDR) { + ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]); + } else if (srgbRequested) { + ok = isSrgbFormat(formats[i].format); + } + if (ok) { + colorFormat = formats[i].format; + colorSpace = formats[i].colorSpace; + break; + } + } + } + + // Although this should be rare, warn when we fail to select a suitable format + if (m_format != SDR) { + VkSurfaceFormatKHR format{}; + format.format = colorFormat; + format.colorSpace = colorSpace; + if (!hdrFormatMatchesVkSurfaceFormat(m_format, format)) { + qWarning("Failed to select a suitable VkFormat for HDR, using format %d as fallback", + colorFormat); + } + } else { + if (srgbRequested && !isSrgbFormat(colorFormat)) { + qWarning("Failed to select a suitable VkFormat for sRGB, using format %d as fallback", + colorFormat); + } + } + +#if QT_CONFIG(wayland) + // On Wayland, only one color management surface can be created at a time without + // triggering a protocol error, and we create one ourselves in some situations. + // To avoid this problem, use VK_COLOR_SPACE_PASS_THROUGH_EXT when supported, + // so that the driver doesn't create a color management surface as well. + const bool hasPassThrough = + std::any_of(formats.begin(), formats.end(), [this](const VkSurfaceFormatKHR &fmt) { + return fmt.format == colorFormat + && fmt.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT; + }); + if (hasPassThrough) { + colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT; + } +#endif + samples = rhiD->effectiveSampleCountBits(m_sampleCount); quint32 presModeCount = 0; diff --git a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan_p.h b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan_p.h index 21044545ad..2c0c7412f3 100644 --- a/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/rhi/qrhivulkan_p.h @@ -251,7 +251,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings bool create() override; void updateResources(UpdateFlags flags) override; - QVarLengthArray sortedBindings; + QVarLengthArray sortedBindings; bool hasDynamicOffset = false; int poolIndex = -1; VkDescriptorSetLayout layout = VK_NULL_HANDLE; @@ -291,7 +291,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings BoundStorageBufferData sbuf; }; }; - QVarLengthArray boundResourceData[QVK_FRAMES_IN_FLIGHT]; + QVarLengthArray boundResourceData[QVK_FRAMES_IN_FLIGHT]; friend class QRhiVulkan; }; @@ -368,6 +368,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets)); inExternal = false; hasShadingRateSet = false; + hasCustomScissorSet = false; + currentViewport = {}; } PassType recordingPass; @@ -390,9 +392,15 @@ struct QVkCommandBuffer : public QRhiCommandBuffer QVarLengthArray activeSecondaryCbStack; bool inExternal; bool hasShadingRateSet; + bool hasCustomScissorSet; + QRhiViewport currentViewport; - struct { - QHash > writtenResources; + struct ComputePassState { + struct AccessFlagsAndIsNew { + VkAccessFlags accessFlags; + bool isNew; + }; + QVarLengthFlatMap writtenResources; void reset() { writtenResources.clear(); } @@ -604,6 +612,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer friend class QRhiVulkan; }; +Q_DECLARE_TYPEINFO(QVkCommandBuffer::ComputePassState::AccessFlagsAndIsNew, Q_RELOCATABLE_TYPE); + struct QVkSwapChain : public QRhiSwapChain { QVkSwapChain(QRhiImplementation *rhi); @@ -633,7 +643,9 @@ struct QVkSwapChain : public QRhiSwapChain int bufferCount = 0; VkSurfaceKHR surface = VK_NULL_HANDLE; VkSurfaceKHR lastConnectedSurface = VK_NULL_HANDLE; - VkFormat colorFormat = VK_FORMAT_B8G8R8A8_UNORM; + const VkFormat defaultColorFormat = VK_FORMAT_B8G8R8A8_UNORM; + const VkFormat defaultSrgbColorFormat = VK_FORMAT_B8G8R8A8_SRGB; + VkFormat colorFormat = VK_FORMAT_UNDEFINED; VkColorSpaceKHR colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; QVkRenderBuffer *ds = nullptr; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; @@ -882,6 +894,7 @@ public: void ensureCommandPoolForNewFrame(); double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok); void printExtraErrorInfo(VkResult err); + void setDefaultScissor(QVkCommandBuffer *cbD); QVulkanInstance *inst = nullptr; QWindow *maybeWindow = nullptr; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext.mm b/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext.mm index ded84c0379..4f4d246df9 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext.mm +++ b/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext.mm @@ -758,8 +758,9 @@ bool QCoreTextFontEngine::shouldSmoothFont() const Q_UNREACHABLE(); } -bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const +bool QCoreTextFontEngine::expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const { + Q_UNUSED(format); return shouldSmoothFont() && fontSmoothing() == Subpixel; } diff --git a/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext_p.h b/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext_p.h index 24cb29c7ce..b9647e0ac9 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/text/coretext/qfontengine_coretext_p.h @@ -77,7 +77,7 @@ public: void doKerning(QGlyphLayout *g, ShaperFlags flags) const override; bool supportsTransformation(const QTransform &transform) const override; - bool expectsGammaCorrectedBlending() const override; + bool expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format = QFontEngine::Format_None) const override; QFontEngine *cloneWithSize(qreal pixelSize) const override; Qt::HANDLE handle() const override; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft.cpp b/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft.cpp index e331a4cc81..04ffa98851 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft.cpp @@ -1127,8 +1127,9 @@ void QFontEngineFT::setDefaultHintStyle(HintStyle style) default_hint_style = style; } -bool QFontEngineFT::expectsGammaCorrectedBlending() const +bool QFontEngineFT::expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const { + Q_UNUSED(format); return stemDarkeningDriver; } @@ -1955,11 +1956,13 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType); err = FT_Render_Glyph(slot, renderMode); - if (err != FT_Err_Ok) - qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE); + if (err != FT_Err_Ok) { + qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph); + return nullptr; + } + info.height = slot->bitmap.rows; info.width = slot->bitmap.width; info.x = slot->bitmap_left; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft_p.h b/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft_p.h index 13cd1bf2bf..4b136f6238 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/text/freetype/qfontengine_ft_p.h @@ -224,7 +224,7 @@ private: GlyphFormat neededFormat, const QTransform &t) override; bool hasInternalCaching() const override { return cacheEnabled; } - bool expectsGammaCorrectedBlending() const override; + bool expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const override; void removeGlyphFromCache(glyph_t glyph) override; int glyphMargin(QFontEngine::GlyphFormat /* format */) override { return 0; } diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qcssparser.cpp b/local/recipes/qt/qtbase/source/src/gui/text/qcssparser.cpp index 7517c7a3de..cd717d81db 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qcssparser.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/qcssparser.cpp @@ -2639,7 +2639,7 @@ bool Parser::parseAnimation(AnimationRule *animationRule) } } if (!decl.isEmpty()) - set.declarations.append(decl); + set.declarations.push_back(std::move(decl)); } while (test(SEMICOLON)); if (!next(RBRACE)) return false; @@ -3046,7 +3046,7 @@ bool Parser::testAndParseUri(QString *uri) index = rewind; return false; } - *uri = args; + *uri = std::move(args); removeOptionalQuotes(uri); return true; } diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qfontengine.cpp b/local/recipes/qt/qtbase/source/src/gui/text/qfontengine.cpp index 4df55d5b89..b61dc28fd7 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qfontengine.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/qfontengine.cpp @@ -255,8 +255,9 @@ bool QFontEngine::supportsTransformation(const QTransform &transform) const return transform.type() < QTransform::TxProject; } -bool QFontEngine::expectsGammaCorrectedBlending() const +bool QFontEngine::expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const { + Q_UNUSED(format); return true; } diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qfontengine_p.h b/local/recipes/qt/qtbase/source/src/gui/text/qfontengine_p.h index 160652e9c7..128a553c7e 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qfontengine_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/text/qfontengine_p.h @@ -261,7 +261,7 @@ public: static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily); virtual bool hasUnreliableGlyphOutline() const; - virtual bool expectsGammaCorrectedBlending() const; + virtual bool expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const; static bool disableEmojiSegmenter(); diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentfragment.cpp b/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentfragment.cpp index 9214c9512c..eb5722b9eb 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentfragment.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentfragment.cpp @@ -867,8 +867,8 @@ bool QTextHtmlImporter::closeTag() if (lists.isEmpty()) break; lists.resize(lists.size() - 1); - if (currentNode->hasCssListIndent) - indent -= currentNode->cssListIndent; + if (closedNode->hasCssListIndent) + indent -= closedNode->cssListIndent; else --indent; blockTagClosed = true; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentlayout.cpp b/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentlayout.cpp index 8ff8d1278b..b2c2886b22 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentlayout.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/qtextdocumentlayout.cpp @@ -3542,7 +3542,7 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi line.setLineWidth(qMax(line.naturalTextWidth(), (right-left).toReal())); if (haveWordOrAnyWrapMode) { - option.setWrapMode(QTextOption::WordWrap); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); tl->setTextOption(option); } } @@ -3905,7 +3905,7 @@ void QTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDo break; } case QTextCharFormat::AlignBaseline: { - QFontMetrics m(f.font()); + QFontMetricsF m(f.font()); qreal descent = m.descent(); item.setDescent(descent); item.setAscent(inlineSize.height() - descent); diff --git a/local/recipes/qt/qtbase/source/src/gui/text/qtextimagehandler.cpp b/local/recipes/qt/qtbase/source/src/gui/text/qtextimagehandler.cpp index 79324b5d36..9fef937785 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/qtextimagehandler.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/qtextimagehandler.cpp @@ -4,15 +4,19 @@ #include "qtextimagehandler_p.h" +#include #include #include #include #include -#include #include -#include -#include +#include +#include #include +#include +#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -50,32 +54,71 @@ static inline QUrl findAtNxFileOrResource(const QString &baseFileName, return QUrl(*name); } -template -static T getAs(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0) +static QImage getImage(QTextDocument *doc, const QTextImageFormat &format, + const qreal devicePixelRatio = 1.0, const QSizeF &size = {}) { qreal sourcePixelRatio = 1.0; QString name; const QUrl url = findAtNxFileOrResource(format.name(), devicePixelRatio, &sourcePixelRatio, &name); const QVariant data = doc->resource(QTextDocument::ImageResource, url); - T result; + // directly provided as QPixmap/QImage or already cached if (data.userType() == QMetaType::QPixmap || data.userType() == QMetaType::QImage) - result = data.value(); - else if (data.metaType() == QMetaType::fromType()) - result.loadFromData(data.toByteArray()); + return data.value(); - if (result.isNull()) { - if (name.isEmpty() || !result.load(name)) - return T(":/qt-project.org/styles/commonstyle/images/file-16.png"_L1); - doc->addResource(QTextDocument::ImageResource, url, result); + // some image formats are scalable (e.g. svg) so we should not store a single + // QImage as QTextDocument::ImageResource to avoid scaling artefacts later on. + // But otoh we don't want to load them on every usage. Therefore cache the result + // in QPixmapCache + const bool canUsePixmapCache = (QThread::isMainThread() + || QGuiApplicationPrivate::platformIntegration()->hasCapability( + QPlatformIntegration::ThreadedPixmaps)); + const auto buildCacheKey = [](const QSizeF &size, qreal dpr) { + return QLatin1String("qt_textimagehandler_") % HexString(size.width()) + % HexString(size.height()) + % HexString(qRound(dpr * 1000)); + }; + const QString cacheKey = canUsePixmapCache + ? buildCacheKey(size * devicePixelRatio, sourcePixelRatio) + : QString(); + + if (canUsePixmapCache) { + QPixmap pm; + if (QPixmapCache::find(cacheKey, &pm)) + return pm.toImage(); } - if (sourcePixelRatio != 1.0) - result.setDevicePixelRatio(sourcePixelRatio); + const auto readImage = [&](auto &&content) { + QImageReader imgReader(content); + if (imgReader.canRead()) { + const bool supportsScaledSize = imgReader.supportsOption(QImageIOHandler::ScaledSize); + if (size.isValid() && supportsScaledSize) + imgReader.setScaledSize((size * devicePixelRatio).toSize()); + QImage result = imgReader.read(); + result.setDevicePixelRatio(sourcePixelRatio); + if (!supportsScaledSize) + doc->addResource(QTextDocument::ImageResource, url, result); + else if (canUsePixmapCache) + QPixmapCache::insert(cacheKey, QPixmap::fromImage(result)); + return result; + } + return QImage(); + }; + + QImage result; + if (data.metaType() == QMetaType::fromType()) { + QByteArray ba(data.toByteArray()); + QBuffer buf(&ba); + result = readImage(&buf); + } + if (result.isNull()) + result = readImage(name); + + if (result.isNull()) + result = QImage(":/qt-project.org/styles/commonstyle/images/file-16.png"_L1); return result; } -template static QSize getSize(QTextDocument *doc, const QTextImageFormat &format) { const bool hasWidth = format.hasProperty(QTextFormat::ImageWidth); @@ -96,10 +139,10 @@ static QSize getSize(QTextDocument *doc, const QTextImageFormat &format) width = qMin(effectiveMaxWidth, width); } - T source; + QImage source; QSize size(width, height); if (!hasWidth || !hasHeight) { - source = getAs(doc, format); + source = getImage(doc, format); QSizeF sourceSize = source.deviceIndependentSize(); if (sourceSize.width() > effectiveMaxWidth) { @@ -122,15 +165,10 @@ static QSize getSize(QTextDocument *doc, const QTextImageFormat &format) } } - qreal scale = 1.0; - QPaintDevice *pdev = doc->documentLayout()->paintDevice(); - if (pdev) { - if (source.isNull()) - source = getAs(doc, format); - if (!source.isNull()) - scale = qreal(pdev->logicalDpiY()) / qreal(qt_defaultDpi()); - } - size *= scale; + const QPaintDevice *pdev = doc->documentLayout()->paintDevice(); + if (pdev) + size *= qreal(pdev->logicalDpiY()) / qreal(qt_defaultDpi()); + return size; } @@ -144,16 +182,14 @@ QSizeF QTextImageHandler::intrinsicSize(QTextDocument *doc, int posInDocument, c Q_UNUSED(posInDocument); const QTextImageFormat imageFormat = format.toImageFormat(); - if (QCoreApplication::instance()->thread() != QThread::currentThread()) - return getSize(doc, imageFormat); - return getSize(doc, imageFormat); + return getSize(doc, imageFormat); } QImage QTextImageHandler::image(QTextDocument *doc, const QTextImageFormat &imageFormat) { Q_ASSERT(doc != nullptr); - return getAs(doc, imageFormat); + return getImage(doc, imageFormat); } void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format) @@ -161,13 +197,8 @@ void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocumen Q_UNUSED(posInDocument); const QTextImageFormat imageFormat = format.toImageFormat(); - if (QCoreApplication::instance()->thread() != QThread::currentThread()) { - const QImage image = getAs(doc, imageFormat, p->device()->devicePixelRatio()); - p->drawImage(rect, image, image.rect()); - } else { - const QPixmap pixmap = getAs(doc, imageFormat, p->device()->devicePixelRatio()); - p->drawPixmap(rect, pixmap, pixmap.rect()); - } + const QImage image = getImage(doc, imageFormat, p->device()->devicePixelRatio(), rect.size()); + p->drawImage(rect, image, image.rect()); } QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp index cd35476b1b..fe7e3877ac 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -72,7 +72,7 @@ QString QWindowsDirectWriteFontDatabase::localeString(IDWriteLocalizedStrings *n return QString(); } -static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch) +QFont::Stretch QWindowsDirectWriteFontDatabase::fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch) { switch (stretch) { case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return QFont::UltraCondensed; @@ -88,12 +88,12 @@ static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch) } } -static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight) +QFont::Weight QWindowsDirectWriteFontDatabase::fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight) { return static_cast(weight); } -static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style) +QFont::Style QWindowsDirectWriteFontDatabase::fromDirectWriteStyle(DWRITE_FONT_STYLE style) { switch (style) { case DWRITE_FONT_STYLE_NORMAL: return QFont::StyleNormal; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h index c8ebdef356..0f0d899d00 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h @@ -22,12 +22,7 @@ QT_REQUIRE_CONFIG(directwrite3); #include "qwindowsfontdatabase_p.h" #include - -struct IDWriteFactory; -struct IDWriteFont; -struct IDWriteFont1; -struct IDWriteFontFamily; -struct IDWriteLocalizedStrings; +#include QT_BEGIN_NAMESPACE @@ -62,6 +57,10 @@ public: return m_populatedFonts.contains(fontFamily); } + static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch); + static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight); + static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style); + protected: void invalidate() override; diff --git a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontdatabasebase.cpp index 10012eae65..036c3c3758 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -1007,6 +1007,7 @@ static const char *ch_TW_tryFonts [] = { }; static const char *kr_tryFonts[] = { + "Malgun Gothic", "Gulim", "Arial", "PMingLiU", diff --git a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index b3d4024387..dd181deb51 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -763,7 +763,7 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, const uint *src = reinterpret_cast(im.constScanLine(y)); uchar *dst = alphaMap.scanLine(y); for (int x=0; xpow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.); + *dst = qGray(*src); ++dst; ++src; } @@ -1864,6 +1864,10 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, IDWriteFontFace3 *face3 = nullptr; if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace3), reinterpret_cast(&face3)))) { + + fontDef.weight = QWindowsDirectWriteFontDatabase::fromDirectWriteWeight(face3->GetWeight()); + fontDef.style = QWindowsDirectWriteFontDatabase::fromDirectWriteStyle(face3->GetStyle()); + IDWriteLocalizedStrings *names; if (SUCCEEDED(face3->GetFaceNames(&names))) { wchar_t englishLocale[] = L"en-us"; @@ -2073,4 +2077,9 @@ QList QWindowsFontEngineDirectWrite::variableAxes() const return m_variableAxes; } +bool QWindowsFontEngineDirectWrite::expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const +{ + return format == QFontEngine::Format_A32; +} + QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index d00558a26f..d03d932a54 100644 --- a/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -115,6 +115,8 @@ public: QList variableAxes() const override; + bool expectsGammaCorrectedBlending(QFontEngine::GlyphFormat format) const override; + private: #if QT_CONFIG(directwritecolrv1) bool traverseColr1(IDWritePaintReader *paintReader, diff --git a/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata.cpp b/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata.cpp index f31596772d..4f21ae7f43 100644 --- a/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata.cpp +++ b/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata.cpp @@ -81,6 +81,8 @@ public: QMap keyValues; }; +QT_DEFINE_QSDP_SPECIALIZATION_DTOR(QTextureFileDataPrivate) + QTextureFileData::QTextureFileData(Mode mode) { d = new QTextureFileDataPrivate; diff --git a/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata_p.h b/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata_p.h index e799157783..25611a3b6d 100644 --- a/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata_p.h +++ b/local/recipes/qt/qtbase/source/src/gui/util/qtexturefiledata_p.h @@ -28,6 +28,7 @@ class QDebug; Q_DECLARE_LOGGING_CATEGORY(lcQtGuiTextureIO) class QTextureFileDataPrivate; +QT_DECLARE_QSDP_SPECIALIZATION_DTOR(QTextureFileDataPrivate) class Q_GUI_EXPORT QTextureFileData { @@ -36,9 +37,13 @@ public: QTextureFileData(Mode mode = ByteArrayMode); QTextureFileData(const QTextureFileData &other); + QTextureFileData(QTextureFileData &&) = default; QTextureFileData &operator=(const QTextureFileData &other); + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QTextureFileData) ~QTextureFileData(); + void swap(QTextureFileData &other) noexcept { d.swap(other.d); } + bool isNull() const; bool isValid() const; @@ -85,7 +90,7 @@ private: friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QTextureFileData &d); }; -Q_DECLARE_TYPEINFO(QTextureFileData, Q_RELOCATABLE_TYPE); +Q_DECLARE_SHARED(QTextureFileData) Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QTextureFileData &d); diff --git a/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames.cpp b/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames.cpp index 09234a7e88..65640bd5ec 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames.cpp +++ b/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames.cpp @@ -54,18 +54,29 @@ uchar Frame::padding() const { Q_ASSERT(validateHeader() == FrameStatus::goodFrame); - if (!flags().testFlag(FrameFlag::PADDED)) + if (!isPadded()) return 0; + Q_ASSERT(buffer.size() > frameHeaderSize); + return buffer[frameHeaderSize]; +} + +bool Frame::isPadded() const +{ + return supportsPaddedFlag() && flags().testFlag(FrameFlag::PADDED); +} + +bool Frame::supportsPaddedFlag() const +{ switch (type()) { case FrameType::DATA: case FrameType::PUSH_PROMISE: case FrameType::HEADERS: - Q_ASSERT(buffer.size() > frameHeaderSize); - return buffer[frameHeaderSize]; + return true; default: - return 0; + break; } + return false; } bool Frame::priority(quint32 *streamID, uchar *weight) const @@ -167,9 +178,10 @@ FrameStatus Frame::validatePayload() const case FrameType::DATA: case FrameType::HEADERS: if (frameFlags.testFlag(FrameFlag::PADDED)) { - if (!size || size < src[0]) + // size must cover the 1-byte pad-length field plus src[0] padding bytes + if (!size || size - 1 < src[0]) return FrameStatus::sizeError; - size -= src[0]; + size -= src[0] + 1; } if (type() == FrameType::HEADERS && frameFlags.testFlag(FrameFlag::PRIORITY)) { if (size < 5) @@ -179,9 +191,10 @@ FrameStatus Frame::validatePayload() const // 6.6 PUSH_PROMISE case FrameType::PUSH_PROMISE: if (frameFlags.testFlag(FrameFlag::PADDED)) { - if (!size || size < src[0]) + // size must cover the 1-byte pad-length field plus src[0] padding bytes + if (!size || size - 1 < src[0]) return FrameStatus::sizeError; - size -= src[0]; + size -= src[0] + 1; } if (size < 4) @@ -200,7 +213,7 @@ quint32 Frame::dataSize() const Q_ASSERT(validatePayload() == FrameStatus::goodFrame); quint32 size = payloadSize(); - if (flags().testFlag(FrameFlag::PADDED)) { + if (isPadded()) { const uchar pad = padding(); // + 1 one for a byte with padding number itself: size -= pad + 1; @@ -237,7 +250,7 @@ const uchar *Frame::dataBegin() const return nullptr; const uchar *src = &buffer[0] + frameHeaderSize; - if (flags().testFlag(FrameFlag::PADDED)) + if (isPadded()) ++src; if (priority()) diff --git a/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames_p.h b/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames_p.h index 6794ab2ce8..de813258c4 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames_p.h +++ b/local/recipes/qt/qtbase/source/src/network/access/http2/http2frames_p.h @@ -41,6 +41,8 @@ struct Q_AUTOTEST_EXPORT Frame FrameFlags flags() const; quint32 payloadSize() const; uchar padding() const; + bool supportsPaddedFlag() const; + bool isPadded() const; // In HTTP/2 a stream's priority is specified by its weight and a stream // (id) it depends on: bool priority(quint32 *streamID = nullptr, diff --git a/local/recipes/qt/qtbase/source/src/network/access/qhttp2connection.cpp b/local/recipes/qt/qtbase/source/src/network/access/qhttp2connection.cpp index 12947f5a31..670cad74fa 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/qhttp2connection.cpp +++ b/local/recipes/qt/qtbase/source/src/network/access/qhttp2connection.cpp @@ -1579,9 +1579,10 @@ void QHttp2Connection::handleDATA() "[%p] Received DATA frame with payload size %u, " "but SETTINGS_MAX_FRAME_SIZE is %u, sending FRAME_SIZE_ERROR", this, inboundFrame.payloadSize(), m_config.maxFrameSize()); - return stream->streamError( - Http2Error::FRAME_SIZE_ERROR, - QLatin1String("DATA payload size exceeds SETTINGS_MAX_FRAME_SIZE")); + if (stream) + return stream->streamError(Http2Error::FRAME_SIZE_ERROR, + QLatin1String("DATA payload size exceeds SETTINGS_MAX_FRAME_SIZE")); + return connectionError(FRAME_SIZE_ERROR, "DATA payload size exceeds SETTINGS_MAX_FRAME_SIZE"); } if (qint32(inboundFrame.payloadSize()) > sessionReceiveWindowSize) { @@ -1800,7 +1801,7 @@ void QHttp2Connection::handleSETTINGS() if (inboundFrame.flags().testFlag(FrameFlag::ACK)) { // RFC 9113, 6.5: Receipt of a SETTINGS frame with the ACK flag set and a length field // value other than 0 MUST be treated as a connection error - if (inboundFrame.payloadSize ()) + if (inboundFrame.payloadSize()) return connectionError(FRAME_SIZE_ERROR, "SETTINGS ACK with data"); if (!waitingForSettingsACK) return connectionError(PROTOCOL_ERROR, "unexpected SETTINGS ACK"); @@ -1814,7 +1815,7 @@ void QHttp2Connection::handleSETTINGS() // RFC 9113, 6.5: A SETTINGS frame with a length other than a multiple of 6 octets MUST be // treated as a connection error (Section 5.4.1) of type FRAME_SIZE_ERROR. // checked in Frame::validateHeader() - Q_ASSERT (inboundFrame.payloadSize() % 6 == 0); + Q_ASSERT(inboundFrame.payloadSize() % 6 == 0); auto src = inboundFrame.dataBegin(); for (const uchar *end = src + inboundFrame.dataSize(); src != end; src += 6) { @@ -2077,11 +2078,16 @@ void QHttp2Connection::handleWINDOW_UPDATE() const auto blockedStreams = std::exchange(m_blockedStreams, {}); for (quint32 blockedStreamID : blockedStreams) { const QPointer stream = m_streams.value(blockedStreamID); - if (!stream || !stream->isActive()) + if (!stream || !stream->isActive() || !stream->isUploadingDATA()) continue; - if (stream->isUploadingDATA() && !stream->isUploadBlocked()) + if (stream->isUploadBlocked()) { + m_blockedStreams.insert(blockedStreamID); + + + } else { QMetaObject::invokeMethod(stream, &QHttp2Stream::maybeResumeUpload, Qt::QueuedConnection); + } } } else { QHttp2Stream *stream = m_streams.value(streamID); diff --git a/local/recipes/qt/qtbase/source/src/network/access/qhttp2protocolhandler.cpp b/local/recipes/qt/qtbase/source/src/network/access/qhttp2protocolhandler.cpp index dbcccd8e94..2283df5f0f 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/qhttp2protocolhandler.cpp +++ b/local/recipes/qt/qtbase/source/src/network/access/qhttp2protocolhandler.cpp @@ -138,6 +138,8 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan if (!h2Connection->isGoingAway()) h2Connection->close(Http2::PROTOCOL_ERROR); }); + connect(h2Connection, &QHttp2Connection::connectionClosed, this, + &QHttp2ProtocolHandler::closeSession); } void QHttp2ProtocolHandler::handleConnectionClosure() diff --git a/local/recipes/qt/qtbase/source/src/network/access/qnetworkreplyhttpimpl.cpp b/local/recipes/qt/qtbase/source/src/network/access/qnetworkreplyhttpimpl.cpp index 9a27da0096..ae03127f90 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/local/recipes/qt/qtbase/source/src/network/access/qnetworkreplyhttpimpl.cpp @@ -808,6 +808,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq case QNetworkAccessManager::DeleteOperation: invalidateCache(); httpRequest.setOperation(QHttpNetworkRequest::Delete); + createUploadByteDevice(); break; case QNetworkAccessManager::CustomOperation: @@ -912,7 +913,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq // connections list. This orphaned list will be cleaned up next time 'thread' emits a signal, // unfortunately that's the finished signal. It leads to a soft-leak so we do this to disconnect // it on deletion so that it cleans up the orphan immediately. - QObject::connect(delegate, &QObject::destroyed, delegate, [threadFinishedConnection]() { + QObject::connect(delegate, &QObject::destroyed, + delegate, [threadFinishedConnection] () mutable { if (bool(threadFinishedConnection)) QObject::disconnect(threadFinishedConnection); }); diff --git a/local/recipes/qt/qtbase/source/src/network/access/qnetworkrequest.h b/local/recipes/qt/qtbase/source/src/network/access/qnetworkrequest.h index b826bb60aa..be936ee921 100644 --- a/local/recipes/qt/qtbase/source/src/network/access/qnetworkrequest.h +++ b/local/recipes/qt/qtbase/source/src/network/access/qnetworkrequest.h @@ -184,14 +184,14 @@ public: std::chrono::seconds tcpKeepAliveIdleTimeBeforeProbes() const; void setTcpKeepAliveIdleTimeBeforeProbes(std::chrono::seconds idle) { - const auto r = q26::saturate_cast(idle.count()); + const auto r = q26::saturating_cast(idle.count()); Q_PRE(q20::cmp_equal(r, idle.count())); doSetIdleTimeBeforeProbes(std::chrono::duration(r)); } std::chrono::seconds tcpKeepAliveIntervalBetweenProbes() const; void setTcpKeepAliveIntervalBetweenProbes(std::chrono::seconds interval) { - const auto r = q26::saturate_cast(interval.count()); + const auto r = q26::saturating_cast(interval.count()); Q_PRE(q20::cmp_equal(r, interval.count())); doSetIntervalBetweenProbes(std::chrono::duration(r)); } @@ -220,7 +220,7 @@ Q_DECLARE_SHARED(QNetworkRequest) #if QT_CONFIG(http) || defined (Q_OS_WASM) int QNetworkRequest::transferTimeout() const { - return q26::saturate_cast(transferTimeoutAsDuration().count()); + return q26::saturating_cast(transferTimeoutAsDuration().count()); } void QNetworkRequest::setTransferTimeout(int timeout) diff --git a/local/recipes/qt/qtbase/source/src/network/doc/qtnetwork.qdocconf b/local/recipes/qt/qtbase/source/src/network/doc/qtnetwork.qdocconf index 12319c5c95..e30d0800c7 100644 --- a/local/recipes/qt/qtbase/source/src/network/doc/qtnetwork.qdocconf +++ b/local/recipes/qt/qtbase/source/src/network/doc/qtnetwork.qdocconf @@ -62,4 +62,5 @@ manifestmeta.highlighted.names = \ "QtNetwork/Torrent Example" # Enforce zero documentation warnings +reportmissingalttextforimages = true warninglimit = 0 diff --git a/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface.cpp b/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface.cpp index 006ad93217..55e3426292 100644 --- a/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface.cpp +++ b/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface.cpp @@ -508,7 +508,12 @@ bool QNetworkAddressEntry::isPermanent() const Not all operating systems support reporting all features. Only the IPv4 addresses are guaranteed to be listed by this class in all platforms. In particular, IPv6 address listing is only supported - on Windows, Linux, \macos and the BSDs. + on Windows, Linux, \macos and the BSDs. Similarly, the interface + type reported by type() may not be available on all platforms. + + \note On Android, the interface type is always reported as \l Unknown, + as the platform does not expose hardware type information for physical + interfaces. \sa QNetworkAddressEntry */ diff --git a/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface_unix.cpp b/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface_unix.cpp index a7bd263a3d..048983576b 100644 --- a/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/network/kernel/qnetworkinterface_unix.cpp @@ -29,13 +29,38 @@ # endif #endif // QT_LINUXBASE -#ifdef Q_OS_REDOX -# define IFNAMSIZ 16 -struct ifreq { char ifr_name[IFNAMSIZ]; }; -#endif - #include +#if defined(__redox__) +// Redox relibc's declares the interface flags and if_nameindex() +// helpers but not struct ifreq (there is no SIOCGIF* ioctl support on Redox). +// The getifaddrs path below still declares a `struct ifreq` to pass to +// getMtu(); the SIOCGIFMTU body is #ifdef-guarded and compiles out, so this +// only needs to be a complete type. Provide a minimal-but-standard layout so +// the network module builds; the ioctls that would use it fail gracefully at +// runtime (mtu stays 0). +# ifndef IFNAMSIZ +# define IFNAMSIZ 16 +# endif +struct ifreq { + char ifr_name[IFNAMSIZ]; + union { + struct sockaddr ifr_addr; + struct sockaddr ifr_dstaddr; + struct sockaddr ifr_broadaddr; + struct sockaddr ifr_netmask; + struct sockaddr ifr_hwaddr; + short ifr_flags; + int ifr_ifindex; + int ifr_metric; + int ifr_mtu; + char ifr_slave[IFNAMSIZ]; + char ifr_newname[IFNAMSIZ]; + char *ifr_data; + }; +}; +#endif // __redox__ + QT_BEGIN_NAMESPACE static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QString &ifname = QString()) @@ -568,13 +593,9 @@ static QList createInterfaces(ifaddrs *rawList) iface->flags = convertFlags(ptr->ifa_flags); if ((socket = openSocket(socket)) >= 0) { -#ifndef Q_OS_REDOX struct ifreq ifr; qstrncpy(ifr.ifr_name, ptr->ifa_name, sizeof(ifr.ifr_name)); iface->mtu = getMtu(socket, &ifr); -#else - iface->mtu = 1500; -#endif } } } diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qhttpsocketengine.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qhttpsocketengine.cpp index b747459d17..2f20f26d15 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qhttpsocketengine.cpp +++ b/local/recipes/qt/qtbase/source/src/network/socket/qhttpsocketengine.cpp @@ -412,8 +412,15 @@ bool QHttpSocketEngine::isReadNotificationEnabled() const void QHttpSocketEngine::setReadNotificationEnabled(bool enable) { Q_D(QHttpSocketEngine); - if (d->readNotificationEnabled == enable) + if (d->readNotificationEnabled == enable) { + // When already enabled, we still need to check for + // buffered data. The inner socket may have data in its user-space + // buffer that won't trigger a new OS-level read notification. + // Without this check, partial reads leave data stranded forever. + if (enable && bytesAvailable() > 0) + emitReadNotification(); return; + } d->readNotificationEnabled = enable; if (enable) { diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp index 974076d581..af34957565 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_unix.cpp @@ -37,6 +37,18 @@ # include #endif +#ifdef __redox__ +// Redox relibc does not define struct in6_pktinfo (IPV6_PKTINFO ancillary data), +// but Qt sizes its cmsg control buffers with sizeof(struct in6_pktinfo) in both +// the send and receive datagram paths. Define it at file scope (Linux layout) — +// crucially OUTSIDE the QT_NO_SCTP guard above, which Redox compiles out. +#include +struct in6_pktinfo { + struct in6_addr ipi6_addr; + unsigned int ipi6_ifindex; +}; +#endif + QT_BEGIN_NAMESPACE /* @@ -148,9 +160,7 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt, case QNativeSocketEngine::ReceiveHopLimit: if (socketProtocol == QAbstractSocket::IPv6Protocol || socketProtocol == QAbstractSocket::AnyIPProtocol) { level = IPPROTO_IPV6; -#ifdef IPV6_RECVHOPLIMIT n = IPV6_RECVHOPLIMIT; -#endif } else if (socketProtocol == QAbstractSocket::IPv4Protocol) { #ifdef IP_RECVTTL // IP_RECVTTL is a non-standard extension supported on some OS level = IPPROTO_IP; @@ -338,6 +348,7 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co return -1; } + /* Sets the socket option \a opt to \a v. */ @@ -1059,12 +1070,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS #endif if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int)) -#ifdef IPV6_HOPLIMIT && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) { -#else - && (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL)) { -#endif static_assert(sizeof(header->hopLimit) == sizeof(int)); memcpy(&header->hopLimit, CMSG_DATA(cmsgptr), sizeof(header->hopLimit)); } @@ -1121,19 +1128,6 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l } if (msg.msg_namelen == sizeof(aa.a6)) { -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT -#ifdef IPV6_HOPLIMIT if (header.hopLimit != -1) { msg.msg_controllen += CMSG_SPACE(sizeof(int)); cmsgptr->cmsg_len = CMSG_LEN(sizeof(int)); @@ -1142,19 +1136,6 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l memcpy(CMSG_DATA(cmsgptr), &header.hopLimit, sizeof(int)); cmsgptr = reinterpret_cast(reinterpret_cast(cmsgptr) + CMSG_SPACE(sizeof(int))); } -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif if (header.ifindex != 0 || !header.senderAddress.isNull()) { struct in6_pktinfo *data = reinterpret_cast(CMSG_DATA(cmsgptr)); memset(data, 0, sizeof(*data)); diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_win.cpp b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_win.cpp index 8530c6ca81..e301b79407 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_win.cpp +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnativesocketengine_win.cpp @@ -1475,6 +1475,10 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) setError(QAbstractSocket::NetworkError, WriteErrorString); q->close(); break; + case WSAEMSGSIZE: + ret = -1; + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; default: break; } diff --git a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h index 8941edc5cc..f24189fb65 100644 --- a/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h +++ b/local/recipes/qt/qtbase/source/src/network/socket/qnet_unix_p.h @@ -22,18 +22,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #if defined(Q_OS_VXWORKS) diff --git a/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver.cpp b/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver.cpp index 4bb78645c8..252e4c3689 100644 --- a/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver.cpp +++ b/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver.cpp @@ -340,7 +340,8 @@ void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket) // QObject dtor, but we only use the pointer value! removeSocketData(quintptr(obj)); }); - auto it = socketData.emplace(quintptr(socket), readyRead, destroyed, std::make_shared()); + auto it = socketData.emplace(quintptr(socket), std::move(readyRead), std::move(destroyed), + std::make_shared()); it->timeoutTimer->setSingleShot(true); it->timeoutTimer->callOnTimeout(q, [this, socket]() { handleHandshakeTimedOut(socket); }); it->timeoutTimer->setInterval(handshakeTimeout); diff --git a/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver_p.h b/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver_p.h index fa8dd36040..ac17e948b5 100644 --- a/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver_p.h +++ b/local/recipes/qt/qtbase/source/src/network/ssl/qsslserver_p.h @@ -48,8 +48,8 @@ public: SocketData(QMetaObject::Connection readyRead, QMetaObject::Connection destroyed, std::shared_ptr &&timer) - : readyReadConnection(readyRead), - destroyedConnection(destroyed), + : readyReadConnection{std::move(readyRead)}, + destroyedConnection{std::move(destroyed)}, timeoutTimer(std::move(timer)) { } diff --git a/local/recipes/qt/qtbase/source/src/platformsupport/fbconvenience/qfbvthandler.cpp b/local/recipes/qt/qtbase/source/src/platformsupport/fbconvenience/qfbvthandler.cpp index 0d835331d6..ebf3450c5d 100644 --- a/local/recipes/qt/qtbase/source/src/platformsupport/fbconvenience/qfbvthandler.cpp +++ b/local/recipes/qt/qtbase/source/src/platformsupport/fbconvenience/qfbvthandler.cpp @@ -85,7 +85,7 @@ QFbVtHandler::QFbVtHandler(QObject *parent) connect(m_signalNotifier, &QSocketNotifier::activated, this, &QFbVtHandler::handleSignal); if (!qEnvironmentVariableIntValue("QT_QPA_NO_SIGNAL_HANDLER")) { - struct sigaction sa; + struct sigaction sa = {}; sa.sa_flags = 0; sa.sa_handler = signalHandler; sigemptyset(&sa.sa_mask); diff --git a/local/recipes/qt/qtbase/source/src/platformsupport/input/vxmouse/qvxmousehandler.cpp b/local/recipes/qt/qtbase/source/src/platformsupport/input/vxmouse/qvxmousehandler.cpp index 3f25728470..d76ae312ae 100644 --- a/local/recipes/qt/qtbase/source/src/platformsupport/input/vxmouse/qvxmousehandler.cpp +++ b/local/recipes/qt/qtbase/source/src/platformsupport/input/vxmouse/qvxmousehandler.cpp @@ -14,7 +14,6 @@ #include #include // overrides QT_OPEN -#include #include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/CMakeLists.txt.orig b/local/recipes/qt/qtbase/source/src/plugins/platforms/CMakeLists.txt.orig new file mode 100644 index 0000000000..498a0772bc --- /dev/null +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/CMakeLists.txt.orig @@ -0,0 +1,62 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(ANDROID) + add_subdirectory(android) +endif() +if(NOT WASM) + add_subdirectory(minimal) +endif() +if(QT_FEATURE_freetype AND NOT WASM) + add_subdirectory(offscreen) +endif() +if(QT_FEATURE_xcb) + add_subdirectory(xcb) +endif() +if(UIKIT AND NOT WATCHOS) + add_subdirectory(ios) +endif() +if(MACOS) + add_subdirectory(cocoa) +endif() +if(WIN32) + add_subdirectory(windows) +endif() +if(QT_FEATURE_direct2d1_1 AND QT_FEATURE_directwrite) + add_subdirectory(direct2d) +endif() +if(QNX) + add_subdirectory(qnx) +endif() +if(QT_FEATURE_eglfs) + add_subdirectory(eglfs) + add_subdirectory(minimalegl) +endif() +if(QT_FEATURE_directfb) + add_subdirectory(directfb) +endif() +if(QT_FEATURE_linuxfb) + add_subdirectory(linuxfb) +endif() +if(QT_FEATURE_vnc AND TARGET Qt::Network) + add_subdirectory(vnc) +endif() +if(FREEBSD) + # add_subdirectory(bsdfb) # TODO: QTBUG-112768 +endif() +if(HAIKU) + # add_subdirectory(haiku) # TODO: QTBUG-112768 +endif() +if(WASM) + add_subdirectory(wasm) +endif() +if(QT_FEATURE_integrityfb) + # add_subdirectory(integrity) # TODO: QTBUG-112768 +endif() +if(QT_FEATURE_vkkhrdisplay) + add_subdirectory(vkkhrdisplay) +endif() +if(QT_FEATURE_wayland) + add_subdirectory(wayland) +endif() + diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjniinput.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjniinput.cpp index 6b8597727e..0826d2f4cd 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjniinput.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjniinput.cpp @@ -232,10 +232,10 @@ namespace QtAndroidInput { QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext(); - const QPoint globalPos(x,y); + const QPoint localPos(x,y); QWindow *window = windowFromId(winId); - const QPoint localPos = window && window->handle() ? - window->handle()->mapFromGlobal(globalPos) : globalPos; + const QPoint globalPos = window && window->handle() ? + window->handle()->mapToGlobal(localPos) : localPos; if (inputContext && qGuiApp) QMetaObject::invokeMethod(inputContext, "longPress", Q_ARG(int, globalPos.x()), Q_ARG(int, globalPos.y())); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjnimain.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjnimain.cpp index 15155ece6e..4802a10418 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjnimain.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/androidjnimain.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.cpp index 1cb12b6a54..5935beeae7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.cpp @@ -225,6 +225,7 @@ QAndroidApkFileEngineIterator::QAndroidApkFileEngineIterator( : QAbstractFileEngineIterator(path, filters, filterNames) { const QString relativePath = QAndroidApkFileEngine::relativePath(path); + m_prefixLength = relativePath.size() + 1; for (QAndroidApkFileEngine::FileInfo &info : *apkFileInfos()) { if (info.relativePath.startsWith(relativePath)) m_infos.append(&info); @@ -245,12 +246,7 @@ bool QAndroidApkFileEngineIterator::advance() QString QAndroidApkFileEngineIterator::currentFileName() const { - return m_infos.at(m_index)->relativePath; -} - -QString QAndroidApkFileEngineIterator::currentFilePath() const -{ - return QAndroidApkFileEngine::apkPath() + "!/" + currentFileName(); + return m_infos.at(m_index)->relativePath.mid(m_prefixLength); } #endif diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.h index c5defcca43..213d085080 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidapkfileengine.h @@ -67,10 +67,10 @@ public: bool advance() override; QString currentFileName() const override; - QString currentFilePath() const override; private: int m_index = -1; + qsizetype m_prefixLength = 0; QList m_infos; }; #endif diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidinputcontext.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidinputcontext.cpp index 7614298814..4096f80c3b 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -633,8 +633,7 @@ void QAndroidInputContext::updateSelectionHandles() if (cpos == anchor || im->anchorRectangle().isNull()) { auto curRect = cursorRectangle(); - QPoint cursorPointGlobal = qPlatformWindow->mapToGlobal( - QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height())); + QPoint cursorPointGlobal = QPoint(curRect.x() + (curRect.width() / 2), curRect.y() + curRect.height()); QPoint cursorPoint(curRect.center().x(), curRect.bottom()); int x = curRect.x(); int y = curRect.y(); @@ -676,11 +675,13 @@ void QAndroidInputContext::updateSelectionHandles() int rightSideOfScreen = platformIntegration->screen()->availableGeometry().right(); if (leftPoint.x() < m_selectHandleWidth) leftPoint.setX(m_selectHandleWidth); + leftPoint = qPlatformWindow->mapFromGlobal(leftPoint); if (rightPoint.x() > rightSideOfScreen - m_selectHandleWidth) rightPoint.setX(rightSideOfScreen - m_selectHandleWidth); + rightPoint = qPlatformWindow->mapFromGlobal(rightPoint); - QPoint editPoint(qPlatformWindow->mapToGlobal(leftRect.united(rightRect).topLeft().toPoint())); + QPoint editPoint(leftRect.united(rightRect).topLeft().toPoint()); uint32_t buttons = readOnly ? EditContext::CopyButton | EditContext::SelectAllButton : EditContext::AllButtons; @@ -953,7 +954,7 @@ void QAndroidInputContext::showInputPanel() else if (qGuiApp->focusObject()->metaObject()->indexOfSignal("cursorPositionChanged()") >= 0) m_updateCursorPosConnection = connect(qGuiApp->focusObject(), SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition())); - QRect rect = screenInputItemRectangle(); + QRect rect = QPlatformInputContext::inputItemRectangle().toRect(); QtAndroidInput::showSoftwareKeyboard(rect.left(), rect.top(), rect.width(), rect.height(), query->value(Qt::ImHints).toUInt(), query->value(Qt::ImEnterKeyType).toUInt()); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 27fbd95e6e..c205727bd9 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -51,8 +51,11 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) // surface is already locked when calling this EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) { - if (QAndroidEventDispatcherStopper::stopped() || - QGuiApplication::applicationState() == Qt::ApplicationSuspended) { + // Avoid early return on initial suspension unless a surface was already created. + // This avoids the multi‑window startup race. + if (m_androidSurfaceCreated && + (QAndroidEventDispatcherStopper::stopped() || + QGuiApplication::applicationState() == Qt::ApplicationSuspended)) { qCDebug(lcQpaWindow) << "Application not active, return existing surface."; return m_eglSurface; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformtheme.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformtheme.cpp index addd1199cf..3d7695fbcf 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -151,12 +151,6 @@ static void setPaletteColor(const QVariantMap &object, palette.setColor(QPalette::Inactive, QPalette::Text, palette.color(QPalette::Inactive, role)); palette.setColor(QPalette::Disabled, QPalette::Text, palette.color(QPalette::Disabled, role)); palette.setColor(QPalette::Current, QPalette::Text, palette.color(QPalette::Current, role)); - - // And for ButtonText - palette.setColor(QPalette::Active, QPalette::ButtonText, palette.color(QPalette::Active, role)); - palette.setColor(QPalette::Inactive, QPalette::ButtonText, palette.color(QPalette::Inactive, role)); - palette.setColor(QPalette::Disabled, QPalette::ButtonText, palette.color(QPalette::Disabled, role)); - palette.setColor(QPalette::Current, QPalette::ButtonText, palette.color(QPalette::Current, role)); } } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformwindow.cpp index 36ea443dfb..7ba82ef766 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -118,7 +118,6 @@ void QAndroidPlatformWindow::raise() { if (m_nativeParentQtWindow.isValid()) { m_nativeParentQtWindow.callMethod("bringChildToFront", nativeViewId()); - QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason); return; } updateSystemUiVisibility(window()->windowStates(), window()->flags()); @@ -240,9 +239,12 @@ void QAndroidPlatformWindow::propagateSizeHints() void QAndroidPlatformWindow::requestActivateWindow() { - // raise() will handle differences between top level and child windows, and requesting focus - if (!blockedByModal()) - raise(); + if (blockedByModal()) + return; + raise(); + // For child windows, raise() only updates "Z-order", so focus must be requested explicitly. + if (m_nativeParentQtWindow.isValid()) + QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason); } void QAndroidPlatformWindow::updateSystemUiVisibility(Qt::WindowStates states, Qt::WindowFlags flags) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 36d2ae4901..6b7ad22fd3 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -269,26 +269,34 @@ void QCocoaGLContext::updateSurfaceFormat() return value; }; - // Resolve color channel bits from GL, rather than NSOpenGLPFAColorSize, - // as the latter is not specific enough (combines all channels). - GLint redBits, greenBits, blueBits; - glGetIntegerv(GL_RED_BITS, &redBits); - glGetIntegerv(GL_GREEN_BITS, &greenBits); - glGetIntegerv(GL_BLUE_BITS, &blueBits); - m_format.setRedBufferSize(redBits); - m_format.setGreenBufferSize(greenBits); - m_format.setBlueBufferSize(blueBits); + const auto pixelFormatAlphaSize = pixelFormatAttribute(NSOpenGLPFAAlphaSize); + + // Resolve color channel bits from GL if possible, as we get individual channels, + // falling back to NSOpenGLPFAColorSize, where we have to assume uniform channels. + if (pixelFormatAttribute(NSOpenGLPFAOpenGLProfile) == NSOpenGLProfileVersionLegacy) { + GLint redBits, greenBits, blueBits; + glGetIntegerv(GL_RED_BITS, &redBits); + glGetIntegerv(GL_GREEN_BITS, &greenBits); + glGetIntegerv(GL_BLUE_BITS, &blueBits); + m_format.setRedBufferSize(redBits); + m_format.setGreenBufferSize(greenBits); + m_format.setBlueBufferSize(blueBits); + } else { + int colorSize = pixelFormatAttribute(NSOpenGLPFAColorSize); + colorSize -= pixelFormatAlphaSize; // The attribute includes the alpha component + colorSize /= 3; + m_format.setRedBufferSize(colorSize); + m_format.setGreenBufferSize(colorSize); + m_format.setBlueBufferSize(colorSize); + } // Surfaces on macOS always have an alpha channel, but unless the user requested // one via setAlphaBufferSize(), which triggered setting NSOpenGLCPSurfaceOpacity // to make the surface non-opaque, we don't want to report back the actual alpha // size, as that will make the user believe the alpha channel can be used for // something useful, when in reality it can't, due to the surface being opaque. - if (m_format.alphaBufferSize() > 0) { - GLint alphaBits; - glGetIntegerv(GL_ALPHA_BITS, &alphaBits); - m_format.setAlphaBufferSize(alphaBits); - } + if (m_format.alphaBufferSize() > 0) + m_format.setAlphaBufferSize(pixelFormatAlphaSize); m_format.setDepthBufferSize(pixelFormatAttribute(NSOpenGLPFADepthSize)); m_format.setStencilBufferSize(pixelFormatAttribute(NSOpenGLPFAStencilSize)); @@ -485,7 +493,11 @@ void QCocoaGLContext::update() } #endif + GLint previousFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFBO); + glBindFramebuffer(GL_FRAMEBUFFER, 0); [m_context update]; + glBindFramebuffer(GL_FRAMEBUFFER, previousFBO); } void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) @@ -587,7 +599,7 @@ QT_END_NAMESPACE @implementation QNoopDisplayDelegate - (void)displayLayer:(CALayer *)layer { - qCWarning(lcQpaOpenGLContext) << "Ignoring display of" << layer << "during [NSOpenGLContext update]"; + qCInfo(lcQpaOpenGLContext) << "Ignoring display of" << layer << "during [NSOpenGLContext update]"; } @end #endif diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoatheme.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoatheme.mm index 52f449db08..a5d45ef162 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -399,10 +399,6 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const case FileIcon: iconType = kGenericDocumentIcon; break; - case ToolBarHorizontalExtensionButton: - return QAppleIconEngine::fromTheme("chevron.forward.2").pixmap(size.toSize()); - case ToolBarVerticalExtensionButton: - return QAppleIconEngine::fromTheme("chevron.down.2").pixmap(size.toSize()); default: break; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoawindow.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoawindow.mm index f6481ea2b4..63f8b08d6d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1481,6 +1481,10 @@ void QCocoaWindow::windowDidChangeScreen() // same screen. currentScreen->requestUpdate(); } + // If there are no exposed windows left on the previous screen + // we can stop its display link if it was running. + if (previousScreen) + previousScreen->maybeStopDisplayLink(); } // ----------------------- NSWindowDelegate callbacks ----------------------- diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview.mm index b00e6375e1..0d7f50557d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview.mm @@ -267,6 +267,14 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper); return; qCDebug(lcQpaWindow) << "Done moving" << self << "to" << self.window; + + // Moving to a new window might result in a new screen. This is normally + // handled for top level windows via windowDidChangeScreen, but for child + // windows we need to handle it manually. + auto *previousScreen = self.previousWindow ? QCocoaScreen::get(self.previousWindow.screen) : nullptr; + auto *currentScreen = self.window ? QCocoaScreen::get(self.window.screen) : nullptr; + if (currentScreen && currentScreen != previousScreen) + m_platformWindow->windowDidChangeScreen(); } // QWindow::setParent() promises that the child window will be clipped diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_drawing.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_drawing.mm index adc19eab4e..877169f2ef 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -12,7 +12,6 @@ if ((self = [super init])) { m_contentLayer = contentLayer; [self addSublayer:contentLayer]; - contentLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; } return self; } @@ -22,6 +21,15 @@ return m_contentLayer; } +- (void)layoutSublayers +{ + // Layout the content layer explicitly, as using a autoresizingMask + // of kCALayerWidthSizable | kCALayerHeightSizable has been seen to + // drift out of sync, resulting in a content layer larger than its + // container layer. + m_contentLayer.frame = self.bounds; +} + - (void)setNeedsDisplay { [self setNeedsDisplayInRect:CGRectInfinite]; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_tablet.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_tablet.mm index bbf39340aa..1cbf22ab00 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_tablet.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/cocoa/qnsview_tablet.mm @@ -167,6 +167,11 @@ static const QPointingDevice *tabletToolInstance(NSEvent *theEvent) break; } + // Assume it's a stylus device if the pointer type is pen + if (device == QInputDevice::DeviceType::Unknown + && pointerType == QPointingDevice::PointerType::Pen) + device = QInputDevice::DeviceType::Stylus; + const auto uniqueID = QPointingDeviceUniqueId::fromNumericId(uid); auto windowSystemId = theEvent.deviceID; const QPointingDevice *ret = QPointingDevicePrivate::queryTabletDevice(device, pointerType, uniqueID, caps, windowSystemId); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/main.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/main.cpp index 3cf7af3dc7..9ddb7a1c3a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/main.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/main.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #include #include "qintegrityfbintegration.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.cpp index 4fe1e2b630..c9204665cc 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #include "qintegrityfbintegration.h" #include "qintegrityfbscreen.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.h index bed7641a57..dc442c924a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbintegration.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #ifndef QINTEGRITYFBINTEGRATION_H #define QINTEGRITYFBINTEGRATION_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.cpp index bfa05b1b47..9e2af2d856 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #include "qintegrityfbscreen.h" #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.h index 30ac10f94c..d140f1e49a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityfbscreen.h @@ -1,5 +1,6 @@ // Copyright (C) 2017 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 +// Qt-Security score:significant reason:default #ifndef QINTEGRITYFBSCREEN_H #define QINTEGRITYFBSCREEN_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.cpp index e79180b659..798819be1b 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2015 Green Hills Software // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qintegrityhidmanager.h" #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.h index 99433f4e93..c696e5a158 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/integrity/qintegrityhidmanager.h @@ -1,5 +1,6 @@ // Copyright (C) 2015 Green Hills Software // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QINTEGRITYHIDMANAGER_P_H #define QINTEGRITYHIDMANAGER_P_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qioscontext.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qioscontext.mm index 67cc33230b..77a8430071 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qioscontext.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qioscontext.mm @@ -194,7 +194,11 @@ void QIOSContext::swapBuffers(QPlatformSurface *surface) return; // Nothing to do FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface); - Q_ASSERT_X(framebufferObject.isComplete, "QIOSContext", "swapBuffers on incomplete FBO"); + if (!framebufferObject.isComplete) { + qCWarning(lcQpaGLContext, "swapBuffers on incomplete framebuffer object (%s). Skipping flush", + qPrintable(fboStatusString(glCheckFramebufferStatus(GL_FRAMEBUFFER)))); + return; + } if (needsRenderbufferResize(surface)) { qCWarning(lcQpaGLContext, "CAEAGLLayer was resized between makeCurrent and swapBuffers, skipping flush"); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosplatformaccessibility.mm index a63c75757e..b3a5304ddc 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosplatformaccessibility.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -54,8 +54,12 @@ void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *even switch (event->type()) { case QAccessible::Announcement: { auto *announcementEvent = static_cast(event); - UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, - announcementEvent->message().toNSString()); + const bool queueAnnouncement = + (announcementEvent->politeness() == QAccessible::AnnouncementPoliteness::Polite); + NSAttributedString *message = [[NSAttributedString alloc] + initWithString:announcementEvent->message().toNSString() + attributes:@{UIAccessibilitySpeechAttributeQueueAnnouncement: @(queueAnnouncement)}]; + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, [message autorelease]); break; } case QAccessible::Focus: { @@ -75,6 +79,13 @@ void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *even UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element); break; } + case QAccessible::StateChanged: + case QAccessible::ValueChanged: { + auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()]; + if (element) + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element); + break; + } case QAccessible::ObjectCreated: case QAccessible::ObjectShow: case QAccessible::ObjectHide: diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.h index 39e426463a..b2c6dd6a17 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.h @@ -55,6 +55,8 @@ private: static void initializeScreens(); void deliverUpdateRequests() const; + bool shouldPauseDisplayLinkWhenInactive() const; + #if !defined(Q_OS_VISIONOS) UIScreen *m_uiScreen = nullptr; QMacNotificationObserver m_screenBrightnessObserver; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.mm index 923818239a..0a893b7b54 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/qiosscreen.mm @@ -23,6 +23,8 @@ #include #include +#include + #include // ------------------------------------------------------------------------- @@ -215,14 +217,16 @@ QIOSScreen::QIOSScreen(UIScreen *screen) } }); - // We're pausing the display link if the application moves out of the active state, - // so make sure to deliver to any windows that need it once the app becomes active. - QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, [this](auto newState) { - if (newState == Qt::ApplicationActive) { - qCDebug(lcQpaApplication) << "Attempting update request delivery after becoming active"; - deliverUpdateRequests(); - } - }); + if (shouldPauseDisplayLinkWhenInactive()) { + // We're pausing the display link if the application moves out of the active state, + // so make sure to deliver to any windows that need it once the app becomes active. + QObject::connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, [this](auto newState) { + if (newState == Qt::ApplicationActive) { + qCDebug(lcQpaApplication) << "Attempting update request delivery after becoming active"; + deliverUpdateRequests(); + } + }); + } #endif // !defined(Q_OS_VISIONOS)) @@ -309,7 +313,8 @@ void QIOSScreen::deliverUpdateRequests() const { bool pauseUpdates = true; - if (QGuiApplication::applicationState() != Qt::ApplicationActive) { + if (shouldPauseDisplayLinkWhenInactive() + && QGuiApplication::applicationState() != Qt::ApplicationActive) { // The applicationWillResignActive documentation describes that the app // should "use this method to pause ongoing tasks, disable timers, and // throttle down OpenGL ES frame rates", so we skip update request @@ -497,6 +502,25 @@ QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height) return QPixmap::fromImage(qt_mac_toQImage(screenshot.CGImage)); } +bool QIOSScreen::shouldPauseDisplayLinkWhenInactive() const +{ + // iPad 7 with iOS 18 has been observed to crash during swapBuffers + // if the user enters split-view mode and drags the divider around. + // This is likely a GL driver issue. To reduce the chance of hitting + // this crash we pause the display link when the app is inactive. + // We limit it to A10 devices, as the crash has not been observed on + // other SoCs. See QTBUG-132314 for more information. + + static const bool isA10GPU = []{ + auto device = MTLCreateSystemDefaultDevice(); + return [device.name containsString:@"A10"]; + }(); + + static const bool pauseWhenInactive = qEnvironmentVariableIntegerValue( + "QT_IOS_PAUSE_DISPLAY_LINK_WHEN_INACTIVE").value_or(isA10GPU); + return pauseWhenInactive; +} + #if !defined(Q_OS_VISIONOS) UIScreen *QIOSScreen::uiScreen() const { diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiaccessibilityelement.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiaccessibilityelement.mm index 54c2f9c100..b77c2fdba2 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiaccessibilityelement.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -112,10 +112,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); if (state.checkable) { if (iface->role() == QAccessible::CheckBox - || iface->role() == QAccessible::RadioButton) - return @""; - - if (iface->role() == QAccessible::Switch) + || iface->role() == QAccessible::RadioButton + || iface->role() == QAccessible::Switch) return state.checked ? @"1" : @"0"; return state.checked @@ -131,7 +129,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); return text->text(0, text->characterCount()).toNSString(); } - return [super accessibilityHint]; + return [super accessibilityValue]; } - (CGRect)accessibilityFrame @@ -143,7 +141,20 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); } QRect rect = iface->rect(); - return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); + CGRect frame = QRectF(rect).toCGRect(); + + // Adjust the frame to ensure focus rectangle aligns with the visually shifted + // content when onscreen keyboard is shown. + UIView *view = self.accessibilityContainer; + if ([view isKindOfClass:[UIView class]]) { + if (UIView *rootView = view.window.rootViewController.view) { + CATransform3D transform = rootView.layer.sublayerTransform; + if (!CATransform3DIsIdentity(transform)) + frame.origin.y += transform.m42; + } + } + + return frame; } - (UIAccessibilityTraits)accessibilityTraits @@ -169,10 +180,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); if (accessibleRole == QAccessible::Button) { traits |= UIAccessibilityTraitButton; } else if (accessibleRole == QAccessible::CheckBox - || accessibleRole == QAccessible::RadioButton) { - if (state.checked) - traits |= UIAccessibilityTraitSelected; - } else if (accessibleRole == QAccessible::Switch) { + || accessibleRole == QAccessible::RadioButton + || accessibleRole == QAccessible::Switch) { traits |= UIAccessibilityTraitToggleButton; } else if (accessibleRole == QAccessible::EditableText) { static auto defaultTextFieldTraits = []{ diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiview.mm b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiview.mm index 3bec044ad8..2d223625ba 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiview.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/ios/quiview.mm @@ -24,6 +24,7 @@ #include #include +Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse") Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") Q_LOGGING_CATEGORY(lcQpaInputEvents, "qt.qpa.input.events") @@ -57,12 +58,8 @@ inline ulong getTimeStamp(UIEvent *event) QHash m_activeTouches; UITouch *m_activePencilTouch; NSMutableArray *m_accessibleElements; - UIPanGestureRecognizer *m_scrollGestureRecognizer; CGPoint m_lastScrollCursorPos; CGPoint m_lastScrollDelta; -#if QT_CONFIG(tabletevent) - UIHoverGestureRecognizer *m_hoverGestureRecognizer; -#endif } + (Class)layerClass @@ -87,27 +84,30 @@ inline ulong getTimeStamp(UIEvent *event) self.multipleTouchEnabled = YES; #endif - m_scrollGestureRecognizer = [[UIPanGestureRecognizer alloc] - initWithTarget:self - action:@selector(handleScroll:)]; + auto scrollGestureRecognizer = [[UIPanGestureRecognizer alloc] + initWithTarget:self action:@selector(handleScroll:)]; // The gesture recognizer should only care about scroll gestures (for now) // Set allowedTouchTypes to empty array here to not interfere with touch events // handled by the UIView. Scroll gestures, even those coming from touch devices, // such as trackpads will still be received as they are not touch events - m_scrollGestureRecognizer.allowedTouchTypes = [NSArray array]; - if (@available(ios 13.4, *)) { - m_scrollGestureRecognizer.allowedScrollTypesMask = UIScrollTypeMaskAll; - } - m_scrollGestureRecognizer.maximumNumberOfTouches = 0; + scrollGestureRecognizer.allowedTouchTypes = @[]; + if (@available(ios 13.4, *)) + scrollGestureRecognizer.allowedScrollTypesMask = UIScrollTypeMaskAll; + scrollGestureRecognizer.maximumNumberOfTouches = 0; m_lastScrollDelta = CGPointZero; m_lastScrollCursorPos = CGPointZero; - [self addGestureRecognizer:m_scrollGestureRecognizer]; + [self addGestureRecognizer:[scrollGestureRecognizer autorelease]]; + + auto mouseHoverGestureRecognizer = [[UIHoverGestureRecognizer alloc] + initWithTarget:self action:@selector(handleMouseHover:)]; + mouseHoverGestureRecognizer.allowedTouchTypes = @[ @(UITouchTypeIndirectPointer) ]; + [self addGestureRecognizer:[mouseHoverGestureRecognizer autorelease]]; #if QT_CONFIG(tabletevent) - m_hoverGestureRecognizer = [[UIHoverGestureRecognizer alloc] - initWithTarget:self - action:@selector(handleHover:)]; - [self addGestureRecognizer:m_hoverGestureRecognizer]; + auto pencilHoverGestureRecognizer = [[UIHoverGestureRecognizer alloc] + initWithTarget:self action:@selector(handlePencilHover:)]; + pencilHoverGestureRecognizer.allowedTouchTypes = @[ @(UITouchTypePencil) ]; + [self addGestureRecognizer:[pencilHoverGestureRecognizer autorelease]]; #endif // Set up layer @@ -147,7 +147,6 @@ inline ulong getTimeStamp(UIEvent *event) - (void)dealloc { [m_accessibleElements release]; - [m_scrollGestureRecognizer release]; [super dealloc]; } @@ -597,6 +596,34 @@ inline ulong getTimeStamp(UIEvent *event) self.platformWindow->window(), timestamp, iosIntegration->touchDevice()); } +- (void)handleMouseHover:(UIHoverGestureRecognizer *)recognizer +{ + if (!self.platformWindow) + return; + + auto *window = self.platformWindow->window(); + auto localPosition = QPointF::fromCGPoint([recognizer locationInView:self]); + auto globalPosition = self.platformWindow->mapToGlobalF(localPosition); + + switch (recognizer.state) { + case UIGestureRecognizerStateBegan: + qCDebug(lcQpaMouse) << "🖱️ enter" << window << "local =" << localPosition; + QWindowSystemInterface::handleEnterEvent(window, localPosition, globalPosition); + break; + case UIGestureRecognizerStateEnded: + qCDebug(lcQpaMouse) << "🖱️ leave" << window; + QWindowSystemInterface::handleLeaveEvent(window); + break; + case UIGestureRecognizerStateChanged: + qCDebug(lcQpaMouse) << "🖱️ move" << "local =" << localPosition << "global =" << globalPosition; + QWindowSystemInterface::handleMouseEvent(window, localPosition, globalPosition, + Qt::NoButton, Qt::NoButton, QEvent::MouseMove); + break; + default: + qCWarning(lcQpaMouse) << "Unknown hover state for" << recognizer; + } +} + - (int)mapPressTypeToKey:(UIPress*)press withModifiers:(Qt::KeyboardModifiers)qtModifiers text:(QString &)text { switch (press.type) { @@ -609,12 +636,17 @@ inline ulong getTimeStamp(UIEvent *event) case UIPressTypePlayPause: return Qt::Key_MediaTogglePlayPause; } if (@available(ios 13.4, *)) { - NSString *charactersIgnoringModifiers = press.key.charactersIgnoringModifiers; - Qt::Key key = QAppleKeyMapper::fromUIKitKey(charactersIgnoringModifiers); + Qt::Key key = QAppleKeyMapper::fromUIKitKey(press.key.keyCode); + if (key != Qt::Key_unknown) + return key; + NSString *charactersIgnoringModifiers = press.key.charactersIgnoringModifiers; + key = QAppleKeyMapper::fromUIKitKey(charactersIgnoringModifiers); + if (key != Qt::Key_unknown) + return key; + key = QAppleKeyMapper::fromNSString(qtModifiers, press.key.characters, + charactersIgnoringModifiers, text); if (key != Qt::Key_unknown) return key; - return QAppleKeyMapper::fromNSString(qtModifiers, press.key.characters, - charactersIgnoringModifiers, text); } return Qt::Key_unknown; } @@ -785,11 +817,18 @@ inline ulong getTimeStamp(UIEvent *event) #endif // QT_CONFIG(wheelevent) #if QT_CONFIG(tabletevent) -- (void)handleHover:(UIHoverGestureRecognizer *)recognizer +- (void)handlePencilHover:(UIHoverGestureRecognizer *)recognizer { if (!self.platformWindow) return; + // Just before lifting the pencil we might receive a hover event, + // but the event's position wrongly reflects the position where the + // pencil was first pressed instead of the current position, and + // semantically it doesn't make sense to send hover before release. + if (m_activePencilTouch) + return; + ulong timeStamp = [[NSProcessInfo processInfo] systemUptime] * 1000; CGFloat zOffset = 0; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/CMakeLists.txt index 0f9deaa00b..c5c02b39be 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/CMakeLists.txt @@ -66,11 +66,9 @@ qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_pps PPS::PPS ) -qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_clipboard AND QT_FEATURE_qqnx_pps +qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_clipboard SOURCES qqnxclipboard.cpp qqnxclipboard.h - LIBRARIES - clipboard ) qt_internal_extend_target(QQnxIntegrationPlugin CONDITION QT_FEATURE_qqnx_imf AND QT_FEATURE_qqnx_pps diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.cpp index e5656d7cb9..a572ba7c6a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "main.h" #include "qqnxintegration.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.h index 155e0ec9a6..b20d3d5e17 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/main.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractcover.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractcover.h index bb3be00364..8aa3c521cb 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractcover.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractcover.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXABSTRACTCOVER_H #define QQNXABSTRACTCOVER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp index 9b1107b7ec..2c5e59bc73 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxabstractnavigator.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.h index fc92592307..ce80c7377c 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractnavigator.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXABSTRACTNAVIGATOR_H #define QQNXABSTRACTNAVIGATOR_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp index 3549bccf40..fbfe6e4867 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxabstractvirtualkeyboard.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h index 8c34cabb20..d8859c16a5 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXABSTRACTVIRTUALKEYBOARD_H #define QQNXABSTRACTVIRTUALKEYBOARD_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.cpp index 4d3b5256b2..f6368eed1c 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxglobal.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.h index b456eb2a62..c9705275d3 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuffer.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXBUFFER_H #define QQNXBUFFER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp index 788cddea87..acafce8059 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxbuttoneventnotifier.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h index c3564cddd1..e18ad41a52 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXBUTTONSEVENTNOTIFIER_H #define QQNXBUTTONSEVENTNOTIFIER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.cpp index 3f27ec8069..5294388765 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.cpp @@ -1,5 +1,7 @@ // Copyright (C) 2011 - 2012 Research In Motion +// Copyright (c) 2020 BlackBerry Limited // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses @@ -8,36 +10,25 @@ #include "qqnxclipboard.h" #include +#include +#include #include +#include #include +#include +#include #include #include -#include + #include QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard"); -// null terminated array -static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0}; - -static QByteArray readClipboardBuff(const char *type) -{ - char *pbuffer; - if (is_clipboard_format_present(type) == 0) { - int size = get_clipboard_data(type, &pbuffer); - if (size != -1 && pbuffer) { - const QByteArray result = QByteArray(pbuffer, size); - free(pbuffer); - return result; - } - } - - return QByteArray(); -} +using namespace Qt::StringLiterals; class QQnxClipboard::MimeData : public QMimeData { @@ -46,18 +37,18 @@ public: MimeData(QQnxClipboard *clipboard) : QMimeData(), m_clipboard(clipboard), - m_userMimeData(0) + m_userMimeData(nullptr), + m_formatsToCheck({u"text/html"_s, + u"text/plain"_s, + u"image/png"_s, + u"image/jpeg"_s, + u"application/x-color"_s}) { Q_ASSERT(clipboard); - - for (int i = 0; typeList[i] != 0; ++i) { - m_formatsToCheck << QString::fromUtf8(typeList[i]); - } } ~MimeData() { - delete m_userMimeData; } void addFormatToCheck(const QString &format) { @@ -67,7 +58,7 @@ public: bool hasFormat(const QString &mimetype) const override { - const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0; + const bool result = m_clipboard->hasFormat(mimetype); qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "result=" << result; return result; } @@ -76,8 +67,8 @@ public: { QStringList result; - Q_FOREACH (const QString &format, m_formatsToCheck) { - if (is_clipboard_format_present(format.toUtf8().constData()) == 0) + for (const QString &format : m_formatsToCheck) { + if (m_clipboard->hasFormat(format)) result << format; } @@ -87,8 +78,7 @@ public: void setUserMimeData(QMimeData *userMimeData) { - delete m_userMimeData; - m_userMimeData = userMimeData; + m_userMimeData.reset(userMimeData); // system clipboard API doesn't allow detection of changes by other applications // simulate an owner change through delayed invocation @@ -99,17 +89,26 @@ public: QMimeData *userMimeData() { - return m_userMimeData; + return m_userMimeData.get(); } protected: QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const override { - qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "preferredType=" << preferredType.name(); - if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0) + qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "preferredType=" << preferredType; + if (!m_clipboard->hasFormat(mimetype)) return QMimeData::retrieveData(mimetype, preferredType); - const QByteArray data = readClipboardBuff(mimetype.toUtf8().constData()); + const QByteArray data = m_clipboard->read(mimetype); + if (mimetype == "application/x-qt-image") { + QBuffer buffer; + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + QImage image; + if (image.load(&buffer, "PNG")) { + return QVariant::fromValue(image); + } + } return QVariant::fromValue(data); } @@ -118,8 +117,7 @@ private Q_SLOTS: { if (m_userMimeData) { qCDebug(lcQpaClipboard) << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats(); - delete m_userMimeData; - m_userMimeData = 0; + m_userMimeData.reset(); m_clipboard->emitChanged(QClipboard::Clipboard); } } @@ -128,12 +126,20 @@ private: QQnxClipboard * const m_clipboard; QSet m_formatsToCheck; - QMimeData *m_userMimeData; + std::unique_ptr m_userMimeData; }; QQnxClipboard::QQnxClipboard() - : m_mimeData(new MimeData(this)) + : m_mimeData(new MimeData(this)), m_serverAvailable(false) { + // The clipboard is only implemented if the desktop option is specified + // and if the QQNX_CLIPBOARD environment variable points to a directory + // that contains a .qnxclipboard node. + if (qEnvironmentVariableIsSet("QQNX_CLIPBOARD")) { + m_clipboardDir = QDir(qEnvironmentVariable("QQNX_CLIPBOARD")); + if (m_clipboardDir.exists(".qnxclipboard")) + m_serverAvailable = true; + } } QQnxClipboard::~QQnxClipboard() @@ -152,12 +158,12 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) if (m_mimeData->userMimeData() && m_mimeData->userMimeData() == data) return; - empty_clipboard(); + clear(); m_mimeData->clear(); m_mimeData->setUserMimeData(data); - if (data == 0) { + if (!data) { emitChanged(QClipboard::Clipboard); return; } @@ -165,13 +171,23 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) const QStringList formats = data->formats(); qCDebug(lcQpaClipboard) << "formats=" << formats; - Q_FOREACH (const QString &format, formats) { - const QByteArray buf = data->data(format); + for (const QString &format : formats) { + QByteArray buf; + + // Handling for image data + if (format == "application/x-qt-image") { + QBuffer buffer(&buf); + buffer.open(QIODevice::WriteOnly); + QImage image = qvariant_cast(data->imageData()); + image.save(&buffer, "PNG"); + } else { + buf = data->data(format); + } if (buf.isEmpty()) continue; - int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data()); + bool ret = write(format, buf); qCDebug(lcQpaClipboard) << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret; if (ret) m_mimeData->addFormatToCheck(format); @@ -193,6 +209,75 @@ QMimeData *QQnxClipboard::mimeData(QClipboard::Mode mode) return m_mimeData; } +QFile QQnxClipboard::fileforFormat(const QString &format) const +{ + // If using a standard file system directory, format names of the standard + // "foo/bar" style cannot be handled properly. + QString fileName = format; + fileName.replace('/', '@'); + return QFile(m_clipboardDir.filePath(fileName)); +} + +bool QQnxClipboard::hasFormat(const QString &format) const +{ + if (!m_serverAvailable) + return false; + + QFile file = fileforFormat(format); + return file.exists() && file.size() > 0; +} + +QByteArray QQnxClipboard::read(const QString &format) const +{ + if (!m_serverAvailable) + return QByteArray(); + + QFile file = fileforFormat(format); + if (!file.open(QIODevice::ReadOnly)) + return QByteArray(); + + return file.readAll(); +} + +bool QQnxClipboard::write(const QString &format, const QByteArray &data) const +{ + if (!m_serverAvailable) + return false; + + QFile file = fileforFormat(format); + if (!file.open(QIODevice::WriteOnly)) + return false; + + return file.write(data) == data.size(); +} + +void QQnxClipboard::clear() +{ + if (!m_serverAvailable) + return; + + // Warning! + // Deletes all files in the given directory. Make sure QQNX_CLIPBOARD is set + // to the mount point of a clipboard service or to a dedicated directory. + // This is double-checked in the constructor, which will not start the + // clipboard unless it points to a directory that contains a ".qnxclipboard" + // node. + m_clipboardDir.refresh(); + QDirIterator itr(m_clipboardDir); + while (itr.hasNext()) { + itr.next(); + QString format = itr.fileName(); + if (format == ".qnxclipboard"_L1) + continue; + if (m_clipboardDir.exists(format)) { + qCDebug(lcQpaClipboard) << "deleting" << format; + bool removed = m_clipboardDir.remove(format); + if (!removed) + qCDebug(lcQpaClipboard) << "Failed to remove" << format; + } + } +} + QT_END_NAMESPACE #include "qqnxclipboard.moc" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.h index 66f862f0dc..aaa26506e9 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxclipboard.h @@ -1,10 +1,14 @@ // Copyright (C) 2011 - 2012 Research In Motion +// Copyright (c) 2020 BlackBerry Limited // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXCLIPBOARD_H #define QQNXCLIPBOARD_H #include +#include +#include #if !defined(QT_NO_CLIPBOARD) #include @@ -24,6 +28,14 @@ public: private: class MimeData; MimeData *m_mimeData; + QDir m_clipboardDir; + bool m_serverAvailable; + + [[nodiscard]] QFile fileforFormat(const QString &format) const; + [[nodiscard]] bool hasFormat(const QString &format) const; + [[nodiscard]] QByteArray read(const QString &format) const; + [[nodiscard]] bool write(const QString &format, const QByteArray &data) const; + void clear(); }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.cpp index 0455eaab46..6e31f4a812 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.cpp @@ -1,11 +1,10 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxglobal.h" #include "qqnxcursor.h" -#include -#include #include #include @@ -13,10 +12,18 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaQnx, "qt.qpa.qnx"); -QQnxCursor::QQnxCursor(screen_context_t context) : m_screenContext(context) +QQnxCursor::QQnxCursor(screen_context_t context) + : m_screenContext(context) + , m_customCursorEnabled(qEnvironmentVariableIntValue("QT_QPA_QNX_CUSTOM_CURSOR")) { } +QQnxCursor::~QQnxCursor() +{ + if (m_session) + screen_destroy_session(m_session); +} + #if !defined(QT_NO_CURSOR) static int mapQtCursorToScreenCursor(int cshape) { @@ -56,28 +63,36 @@ static int mapQtCursorToScreenCursor(int cshape) void QQnxCursor::changeCursor(QCursor *windowCursor, QWindow *window) { - qCDebug(lcQpaQnx) << "QQnxCursor::changeCursor() - shape:" << windowCursor->shape() - << "window:" << window; - if (!window || !window->winId()) - return; - if (windowCursor && windowCursor->shape() != m_currentCShape) { - m_currentCShape = windowCursor->shape(); - errno = 0; - int cursorShape = mapQtCursorToScreenCursor(windowCursor->shape()); - screen_window_t screenWindow = reinterpret_cast(window->winId()); + // Custom cursor support requires cursors to be declared in the BSP graphics.conf. + // Calling screen_flush_context() without that configuration freezes input, + // so this feature is opt-in via QT_QPA_QNX_CUSTOM_CURSOR. + if (m_customCursorEnabled) { + if (!windowCursor || !window || !window->winId()) + return; - if (!m_session) { - Q_SCREEN_CHECKERROR(screen_create_session_type(&m_session, m_screenContext, + qCDebug(lcQpaQnx) << "QQnxCursor::changeCursor() - shape:" << windowCursor->shape() + << "window:" << window; + + if (windowCursor->shape() != m_currentCShape) { + m_currentCShape = windowCursor->shape(); + int cursorShape = mapQtCursorToScreenCursor(windowCursor->shape()); + screen_window_t screenWindow = reinterpret_cast(window->winId()); + + if (!m_session) { + Q_SCREEN_CHECKERROR(screen_create_session_type(&m_session, m_screenContext, SCREEN_EVENT_POINTER), - "failed to create session type"); + "failed to create session type"); + if (!m_session) + return; + } + Q_SCREEN_CHECKERROR(screen_set_session_property_pv(m_session, SCREEN_PROPERTY_WINDOW, + (void**) &screenWindow), + "Failed to set window property"); + Q_SCREEN_CHECKERROR(screen_set_session_property_iv(m_session, SCREEN_PROPERTY_CURSOR, + &cursorShape), "Failed to set cursor shape"); + Q_SCREEN_CHECKERROR(screen_flush_context(m_screenContext, 0), + "Failed to flush screen context"); } - Q_SCREEN_CHECKERROR(screen_set_session_property_pv(m_session, SCREEN_PROPERTY_WINDOW, - (void**) &screenWindow), - "Failed to set window property"); - Q_SCREEN_CHECKERROR(screen_set_session_property_iv(m_session, SCREEN_PROPERTY_CURSOR, - &cursorShape), "Failed to set cursor shape"); - Q_SCREEN_CHECKERROR(screen_flush_context(m_screenContext, 0), - "Failed to flush screen context"); } } #endif diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.h index 16292c17b5..334cd24a43 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxcursor.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXCURSOR_H #define QQNXCURSOR_H @@ -17,6 +18,7 @@ class QQnxCursor : public QPlatformCursor { public: QQnxCursor(screen_context_t context); + ~QQnxCursor(); #if !defined(QT_NO_CURSOR) void changeCursor(QCursor *windowCursor, QWindow *window) override; @@ -30,6 +32,7 @@ private: screen_context_t m_screenContext; screen_session_t m_session = 0; int m_currentCShape = 0; + bool m_customCursorEnabled = false; }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.cpp index 854ad46c3d..185244479f 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxeglwindow.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.h index 548d9be1ee..4643d7ed30 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXEGLWINDOW_H #define QQNXEGLWINDOW_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.cpp index 8c83a245d5..b91e63cd0d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2018 QNX Software Systems. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxforeignwindow.h" #include "qqnxintegration.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.h index 83857c0c5d..b18a281ec7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxforeignwindow.h @@ -1,5 +1,6 @@ // Copyright (C) 2018 QNX Software Systems. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXFOREIGNWINDOW_H #define QQNXFOREIGNWINDOW_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.cpp index 3d8fecf88b..e6fd5fc106 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -1,10 +1,12 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxglcontext.h" #include "qqnxintegration.h" #include "qqnxscreen.h" #include "qqnxeglwindow.h" +#include "qqnxwindow.h" #include "private/qeglconvenience_p.h" @@ -55,10 +57,9 @@ void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { qCDebug(lcQpaGLContext) << Q_FUNC_INFO; - QEGLPlatformContext::swapBuffers(surface); - QQnxEglWindow *platformWindow = static_cast(surface); platformWindow->windowPosted(); + QEGLPlatformContext::swapBuffers(surface); } void QQnxGLContext::doneCurrent() diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.h index 96e2865da1..ed61d70d84 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglcontext.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXGLCONTEXT_H #define QQNXGLCONTEXT_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.cpp index 9cfc328e8f..486ae8eef8 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.h index 455edc23dc..fac5935122 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxglobal.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXGLOBAL_H #define QQNXGLOBAL_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp index cd41ebb8c2..90852bec0c 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxinputcontext_imf.h" #include "qqnxabstractvirtualkeyboard.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.h index a20ec6727c..01e65f397a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_imf.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXINPUTCONTEXT_H #define QQNXINPUTCONTEXT_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp index 7789b2830a..da6fa19ef1 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxinputcontext_noimf.h" #include "qqnxabstractvirtualkeyboard.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h index 7f5e1ded3e..a1992387dd 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXINPUTCONTEXT_H #define QQNXINPUTCONTEXT_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.cpp index 1a60bf064c..ba13d6ca85 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses @@ -31,7 +32,6 @@ #if QT_CONFIG(qqnx_pps) # include "qqnxbuttoneventnotifier.h" -# include "qqnxclipboard.h" #endif #if QT_CONFIG(qqnx_imf) @@ -40,6 +40,10 @@ # include "qqnxinputcontext_noimf.h" #endif +#if !defined(QT_NO_CLIPBOARD) +# include "qqnxclipboard.h" +#endif + #include #include @@ -445,11 +449,9 @@ QPlatformNativeInterface *QQnxIntegration::nativeInterface() const QPlatformClipboard *QQnxIntegration::clipboard() const { qCDebug(lcQpaQnx) << Q_FUNC_INFO; - -#if QT_CONFIG(qqnx_pps) if (!m_clipboard) m_clipboard = new QQnxClipboard; -#endif + return m_clipboard; } #endif diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.h index 4de1dccca8..9b47bbb398 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxintegration.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXINTEGRATION_H #define QQNXINTEGRATION_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxkeytranslator.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxkeytranslator.h index d48792c10e..abc2da53d9 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxkeytranslator.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxkeytranslator.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXKEYTRANSLATOR_H #define QQNXKEYTRANSLATOR_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.cpp index 2aa7f253ef..fad318183b 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxlgmon.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.h index 50344b6774..2273c4569d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxlgmon.h @@ -1,5 +1,6 @@ // Copyright (C) 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXLGMON_H #define QQNXLGMON_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.cpp index 2731e0eea4..9a779b642e 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxnativeinterface.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.h index 9363e1baee..973d4c5fdf 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnativeinterface.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXNATIVEINTERFACE_H #define QQNXNATIVEINTERFACE_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp index 7580e560aa..698929b6fc 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxnavigatoreventhandler.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h index 826c9a0ff9..1562885284 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXNAVIGATOREVENTHANDLER_H #define QQNXNAVIGATOREVENTHANDLER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp index 44c71dad52..6a00f8d27a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxnavigatoreventnotifier.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h index 66100ece3f..4101b637e5 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXNAVIGATOREVENTNOTIFIER_H #define QQNXNAVIGATOREVENTNOTIFIER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp index 3a2fee0afb..3649963d24 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxnavigatorpps.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.h index 889b9f62eb..3af36bd852 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxnavigatorpps.h @@ -1,5 +1,6 @@ // Copyright (C) 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXNAVIGATORPPS_H #define QQNXNAVIGATORPPS_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp index dd7de809af..92fb0e17af 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxrasterbackingstore.h" #include "qqnxrasterwindow.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.h index 13ef42f61e..88b7484940 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterbackingstore.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXRASTERWINDOWSURFACE_H #define QQNXRASTERWINDOWSURFACE_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.cpp index b972dab617..f75c6592f0 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 - 2014 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxglobal.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.h index 09d772bb69..ee1a7615ed 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxrasterwindow.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXRASTERWINDOW_H #define QQNXRASTERWINDOW_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.cpp index 4ac5158cca..757b673ee0 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.h index 17b282bdc1..b736027639 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreen.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QBBSCREEN_H #define QBBSCREEN_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventfilter.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventfilter.h index bc6d2720f4..6b0de36180 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventfilter.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventfilter.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXSCREENEVENTFILTER_H #define QQNXSCREENEVENTFILTER_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp index 98ad02ca9b..f9cf10b624 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses @@ -13,6 +14,8 @@ #include "qqnxscreeneventfilter.h" #include "qqnxscreentraits.h" +#include "qqnxwindow.h" + #include #include @@ -244,6 +247,8 @@ void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventTh m_eventThread = eventThread; connect(m_eventThread, &QQnxScreenEventThread::eventsPending, this, &QQnxScreenEventHandler::processEvents); + connect(m_eventThread, &QQnxScreenEventThread::postEventReceived, + this, &QQnxScreenEventHandler::processPostEvent); } void QQnxScreenEventHandler::processEvents() @@ -805,4 +810,13 @@ void QQnxScreenEventHandler::handleManagerEvent(screen_event_t event) } } +void QQnxScreenEventHandler::processPostEvent(screen_window_t qnxWindow) +{ + QWindow *w = QQnxIntegration::instance()->window(qnxWindow); + if (!w) + return; + if (QQnxWindow *platformWindow = static_cast(w->handle())) + platformWindow->handlePostEvent(); +} + #include "moc_qqnxscreeneventhandler.cpp" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.h index 1e7ce98713..94e146ef49 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventhandler.h @@ -1,5 +1,6 @@ // Copyright (C) 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXSCREENEVENTHANDLER_H #define QQNXSCREENEVENTHANDLER_H @@ -43,6 +44,7 @@ protected: private Q_SLOTS: void processEvents(); + void processPostEvent(screen_window_t window); private: void handleKeyboardEvent(screen_event_t event); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp index 6b4ffc3962..5cb3c7164d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2017 QNX Software Systems. All rights reserved. // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxglobal.h" @@ -17,6 +18,7 @@ static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0; static const int c_armCode = _PULSE_CODE_MINAVAIL + 1; static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2; +static const int c_postCode = _PULSE_CODE_MINAVAIL + 3; #if !defined(screen_register_event) int screen_register_event(screen_context_t, struct sigevent *event) @@ -53,6 +55,7 @@ QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context) } screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &m_screenEvent); + qRegisterMetaType("screen_window_t"); } QQnxScreenEventThread::~QQnxScreenEventThread() @@ -92,6 +95,42 @@ void QQnxScreenEventThread::armEventsPending(int count) MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_armCode, count); } +bool QQnxScreenEventThread::registerUpdateNotification(screen_window_t window) +{ + struct sigevent evt; + SIGEV_PULSE_INIT(&evt, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_postCode, 0); + evt.sigev_value.sival_ptr = window; + if (screen_register_event(m_screenContext, &evt) == -1) { + qWarning() << "QQnxScreenEventThread: Failed to register post event for window" << window; + return false; + } + int rc = screen_notify(m_screenContext, SCREEN_NOTIFY_UPDATE, window, &evt); + qCDebug(lcQpaScreenEvents) << "registerUpdateNotification window=" << window << "rc=" << rc; + if (rc != 0) { + qWarning() << "screen_notify(SCREEN_NOTIFY_UPDATE) failed for window=" << window << strerror(errno); + screen_unregister_event(&evt); + return false; + } + m_postEvents.insert(window, evt); + return true; +} + +void QQnxScreenEventThread::unregisterUpdateNotification(screen_window_t window) +{ + int rc = screen_notify(m_screenContext, SCREEN_NOTIFY_UPDATE, window, nullptr); + qCDebug(lcQpaScreenEvents) << "unregisterUpdateNotification window=" << window << "rc=" << rc; + if (m_postEvents.contains(window)) { + screen_unregister_event(&m_postEvents[window]); + m_postEvents.remove(window); + } +} + +void QQnxScreenEventThread::handlePostPulse(const struct _pulse &msg) +{ + screen_window_t window = static_cast(msg.value.sival_ptr); + Q_EMIT postEventReceived(window); +} + void QQnxScreenEventThread::handleScreenPulse(const struct _pulse &msg) { Q_UNUSED(msg); @@ -120,6 +159,8 @@ void QQnxScreenEventThread::handlePulse(const struct _pulse &msg) handleScreenPulse(msg); else if (msg.code == c_armCode) handleArmPulse(msg); + else if (msg.code == c_postCode) + handlePostPulse(msg); else qWarning() << "Unexpected pulse" << msg.code; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.h index 482cd5c967..b58fcda76e 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreeneventthread.h @@ -1,18 +1,23 @@ // Copyright (C) 2017 QNX Software Systems. All rights reserved. // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXSCREENEVENTTHREAD_H #define QQNXSCREENEVENTTHREAD_H #include #include +#include #include #include QT_BEGIN_NAMESPACE +Q_DECLARE_OPAQUE_POINTER(screen_window_t) +Q_DECLARE_METATYPE(screen_window_t) + class QQnxScreenEventThread : public QThread { Q_OBJECT @@ -23,22 +28,27 @@ public: screen_context_t context() const { return m_screenContext; } void armEventsPending(int count); + bool registerUpdateNotification(screen_window_t window); + void unregisterUpdateNotification(screen_window_t window); protected: void run() override; Q_SIGNALS: void eventsPending(); + void postEventReceived(screen_window_t window); private: void handleScreenPulse(const struct _pulse &msg); void handleArmPulse(const struct _pulse &msg); + void handlePostPulse(const struct _pulse &msg); void handlePulse(const struct _pulse &msg); void shutdown(); int m_channelId; int m_connectionId; struct sigevent m_screenEvent; + QHash m_postEvents; screen_context_t m_screenContext; bool m_emitNeededOnNextScreenPulse = true; int m_screenPulsesSinceLastArmPulse = 0; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreentraits.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreentraits.h index 983ef53048..ed25171dc0 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreentraits.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxscreentraits.h @@ -1,5 +1,6 @@ // Copyright (C) 2018 QNX Software Systems. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXSCREENTRAITS_H #define QQNXSCREENTRAITS_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.cpp index 379bb63507..b086e1e60e 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxservices.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.h index dfe385bf76..dacc514e45 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxservices.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXSERVICES_H #define QQNXSERVICES_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp index 5eceacef95..2a4d350900 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #include "qqnxvirtualkeyboardpps.h" #include "qqnxscreen.h" diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h index 8f1d390760..f5cfd05072 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2012 Research In Motion // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef VIRTUALKEYBOARDPPS_H #define VIRTUALKEYBOARDPPS_H diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.cpp index c973c2628e..af606e08af 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses @@ -9,6 +10,7 @@ #include "qqnxintegration.h" #include "qqnxscreen.h" #include "qqnxlgmon.h" +#include "qqnxscreeneventthread.h" #include @@ -285,12 +287,15 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_ QQnxWindow::~QQnxWindow() { qCDebug(lcQpaWindow) << "window =" << window(); + *m_alive = false; // Qt should have already deleted the children before deleting the parent. Q_ASSERT(m_childWindows.size() == 0); // Remove from plugin's window mapper QQnxIntegration::instance()->removeWindow(m_window); + if (m_postEventRegistered) + QQnxIntegration::instance()->m_screenEventThread->unregisterUpdateNotification(m_window); // Remove from parent's Hierarchy. removeFromParent(); @@ -805,6 +810,8 @@ void QQnxWindow::initWindow() // Add window to plugin's window mapper QQnxIntegration::instance()->addWindow(m_window, window()); + m_postEventRegistered = + QQnxIntegration::instance()->m_screenEventThread->registerUpdateNotification(m_window); // Qt never calls these setters after creating the window, so we need to do that ourselves here setWindowState(window()->windowState()); @@ -915,6 +922,10 @@ void QQnxWindow::applyWindowState() void QQnxWindow::windowPosted() { + if (m_postEventRegistered) { + m_waitingForPost.storeRelease(1); + } + if (m_cover) { m_cover->updateCover(); qqnxLgmonFramePosted(true); // for performance measurements @@ -966,6 +977,50 @@ void QQnxWindow::setWindowTitle(const QString &title) } } +void QQnxWindow::requestUpdate() +{ + Q_ASSERT(hasPendingUpdateRequest()); + + if (!m_postEventRegistered) { + qCDebug(lcQpaWindow) << "requestUpdate: post event not registered, using fallback timer" << window(); + QPlatformWindow::requestUpdate(); + return; + } + + if (m_waitingForPost.loadAcquire()) { + qCDebug(lcQpaWindow) << "requestUpdate: frame in-flight, deferring" << window(); + return; + } + + if (m_fallbackQueued.testAndSetRelaxed(0, 1)) { + QSharedPointer alive = m_alive; + QMetaObject::invokeMethod(window(), [this, alive]() { + if (!*alive) + return; + m_fallbackQueued.storeRelaxed(0); + if (m_waitingForPost.loadAcquire()) + return; + if (hasPendingUpdateRequest()) + deliverUpdateRequest(); + }, Qt::QueuedConnection); + } +} + +void QQnxWindow::handlePostEvent() +{ + if (!m_waitingForPost.testAndSetAcquire(1, 0)) { + qCDebug(lcQpaWindow) << "handlePostEvent: duplicate/early pulse, ignoring" << window(); + return; + } + + qCDebug(lcQpaWindow) << "handlePostEvent: post pulse received" << window(); + + if (isExposed() && hasPendingUpdateRequest()) { + qCDebug(lcQpaWindow) << "handlePostEvent: delivering update" << window(); + deliverUpdateRequest(); + } +} + void QQnxWindow::notifyManager(const QString &msg) { screen_event_t ev; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.h index 7c9442f9e7..a58df0cf19 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/qnx/qqnxwindow.h @@ -1,5 +1,6 @@ // Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default #ifndef QQNXWINDOW_H #define QQNXWINDOW_H @@ -77,6 +78,9 @@ public: void setWindowTitle(const QString &title); + void requestUpdate() override; + void handlePostEvent(); + protected: virtual int pixelFormat() const = 0; virtual void resetBuffers() = 0; @@ -129,6 +133,11 @@ private: DesktopNotifyPosition = 0x2, DesktopNotifyVisible = 0x2 }; + + QAtomicInt m_waitingForPost = 0; + QAtomicInt m_fallbackQueued = 0; + bool m_postEventRegistered = false; + QSharedPointer m_alive { new bool(true) }; }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmaccessibility.cpp index 86863d9628..3fb14595fc 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -56,7 +56,7 @@ QWasmAccessibility::QWasmAccessibility() // Register accessibility element event handler QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); + m_eventHandlerIndex = suspendResume->registerEventHandler([this](const emscripten::val event){ this->handleEventFromHtmlElement(event); }); @@ -66,7 +66,6 @@ QWasmAccessibility::~QWasmAccessibility() { // Remove accessibility element event handler QWasmSuspendResumeControl *suspendResume = QWasmSuspendResumeControl::get(); - Q_ASSERT(suspendResume); suspendResume->removeEventHandler(m_eventHandlerIndex); s_instance = nullptr; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index b47473f9fd..53d0603ba6 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -9,8 +9,8 @@ QT_BEGIN_NAMESPACE -QWasmEventDispatcher::QWasmEventDispatcher(std::shared_ptr suspendResume) - :QEventDispatcherWasm(suspendResume) +QWasmEventDispatcher::QWasmEventDispatcher() + :QEventDispatcherWasm() { } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.h index 2f5ed49022..ca6a7c88a8 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmeventdispatcher.h @@ -16,7 +16,7 @@ class QWasmSuspendResumeControl; class QWasmEventDispatcher : public QEventDispatcherWasm { public: - QWasmEventDispatcher(std::shared_ptr suspendResume); + QWasmEventDispatcher(); protected: bool sendPostedEvents() override; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp index 1e8e0150c2..fb2a05991d 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp @@ -113,6 +113,9 @@ void QWasmFileDialogHelper::onOpenDialogClosed(bool accepted, std::vectorquit(); return; } @@ -139,6 +142,9 @@ void QWasmFileDialogHelper::onSaveDialogClosed(bool accepted, qstdweb::FileSyste { if (!accepted) { emit reject(); + + if (m_eventLoop) + m_eventLoop->quit(); return; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasminputcontext.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasminputcontext.cpp index a4370bd0b3..eb6aa8bf21 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasminputcontext.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasminputcontext.cpp @@ -147,15 +147,13 @@ void QWasmInputContext::inputCallback(emscripten::val event) } event.call("stopImmediatePropagation"); -#if QT_CONFIG(clipboard) } else if (!inputTypeString.compare("insertFromPaste")) { - insertText(QGuiApplication::clipboard()->text()); + insertText(inputStr); event.call("stopImmediatePropagation"); // These can be supported here, // But now, keyCallback in QWasmWindow // will take them as exceptions. //} else if (!inputTypeString.compare("deleteByCut")) { -#endif } else { qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType \"" << inputType.as() << "\" is not supported in Qt yet"; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.cpp index 95e32de31a..f92567d461 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -96,8 +96,7 @@ EMSCRIPTEN_BINDINGS(qtQWasmIntegraton) QWasmIntegration *QWasmIntegration::s_instance; QWasmIntegration::QWasmIntegration() - : m_suspendResume(std::make_shared()) // create early in order to register event handlers at startup - , m_fontDb(nullptr) + : m_fontDb(nullptr) , m_desktopServices(nullptr) #if QT_CONFIG(clipboard) , m_clipboard(new QWasmClipboard) @@ -178,7 +177,7 @@ QWasmIntegration::~QWasmIntegration() elementAndScreen.wasmScreen->deleteScreen(); m_screens.clear(); - + delete m_clipboard; s_instance = nullptr; } @@ -277,7 +276,7 @@ QPlatformFontDatabase *QWasmIntegration::fontDatabase() const QAbstractEventDispatcher *QWasmIntegration::createEventDispatcher() const { - return new QWasmEventDispatcher(m_suspendResume); + return new QWasmEventDispatcher(); } QVariant QWasmIntegration::styleHint(QPlatformIntegration::StyleHint hint) const diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.h index 107b910ab4..81041e629f 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmintegration.h @@ -98,9 +98,6 @@ private: QWasmScreen *wasmScreen; }; - // m_suspendResume should be created first and destroyed early as other fields depend on it - std::shared_ptr m_suspendResume; - mutable QWasmFontDatabase *m_fontDb; mutable QWasmServices *m_desktopServices; mutable QHash m_backingStores; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmscreen.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmscreen.cpp index bc8d817524..856a61d7d4 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h index 1193d9fd66..ee922f9446 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/hardwareintegration/qwaylandclientbufferintegration_p.h @@ -18,7 +18,7 @@ #include #include -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && QT_CONFIG(egl) #include #endif @@ -52,35 +52,9 @@ public: virtual bool supportsWindowDecoration() const { return false; } virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) - virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ virtual bool canCreatePlatformOffscreenSurface() const { return false; } -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && QT_CONFIG(egl) + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; virtual QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay contextDisplay, QOpenGLContext *shareContext) const = 0; virtual QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const { Q_UNUSED(surface); return nullptr; } #endif @@ -91,33 +65,9 @@ public: EglContext }; virtual void *nativeResource(NativeResource /*resource*/) { return nullptr; } -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) -#if QT_CONFIG(opengl) #if QT_CONFIG(opengl) virtual void *nativeResourceForContext(NativeResource /*resource*/, QPlatformOpenGLContext */*context*/) { return nullptr; } -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ -#endif /* QT_CONFIG(opengl) */ +#endif }; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/hardwareintegration/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/hardwareintegration/CMakeLists.txt index 391bd1e48e..9ff56d69f9 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/hardwareintegration/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/hardwareintegration/CMakeLists.txt @@ -19,7 +19,7 @@ endif() if(QT_FEATURE_wayland_libhybris_egl_server_buffer) add_subdirectory(libhybris-egl-server) endif() -if(FALSE AND QT_FEATURE_wayland_shm_emulation_server_buffer) # disabled for Redox (QSharedMemory locking still not runtime-proven on clean rebuilds) +if(QT_FEATURE_wayland_shm_emulation_server_buffer) add_subdirectory(shm-emulation-server) endif() if(QT_FEATURE_wayland_dmabuf_server_buffer) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 6220dfa799..9af1758271 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -311,6 +311,18 @@ void QWaylandXdgSurface::Popup::grab(QWaylandInputDevice *seat, uint serial) m_grabbing = true; } +void QWaylandXdgSurface::Popup::reposition() +{ + if (version() < XDG_POPUP_REPOSITIONED_SINCE_VERSION) + return; + + std::unique_ptr positioner = m_xdgSurface->createPositioner(m_xdgSurface->window()->transientParent()); + m_waitingForRepositionSerial++; + xdg_popup::reposition(positioner->object(), m_waitingForRepositionSerial); + m_waitingForReposition = true; + m_xdgSurface->window()->updateExposure(); +} + void QWaylandXdgSurface::Popup::xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height) { m_pendingGeometry = QRect(x, y, width, height); @@ -580,7 +592,7 @@ bool QWaylandXdgSurface::requestActivate() // At least GNOME requires to request the token in order to get the // focus stealing prevention indication, so requestXdgActivationToken call // is still necessary in that case. - const auto wlWindow = focusWindow ? static_cast(focusWindow->handle()) : m_window; + const auto wlWindow = focusWindow && focusWindow->handle() ? static_cast(focusWindow->handle()) : m_window; QString appId; if (const auto xdgSurface = qobject_cast(wlWindow->shellSurface())) @@ -690,17 +702,24 @@ void QWaylandXdgSurface::setWindowPosition(const QPoint &position) { Q_UNUSED(position); - if (!m_popup) - return; + if (m_popup) + m_popup->reposition(); +} - if (m_popup->version() < XDG_POPUP_REPOSITIONED_SINCE_VERSION) - return; +void QWaylandXdgSurface::setWindowSize(const QSize &size) +{ + Q_UNUSED(size); - std::unique_ptr positioner = createPositioner(m_window->transientParent()); - m_popup->m_waitingForRepositionSerial++; - m_popup->reposition(positioner->object(), m_popup->m_waitingForRepositionSerial); - m_popup->m_waitingForReposition = true; - window()->updateExposure(); + if (m_popup) + m_popup->reposition(); +} + +void QWaylandXdgSurface::setWindowGeometry(const QRect &rect) +{ + Q_UNUSED(rect); + + if (m_popup) + m_popup->reposition(); } static QtWayland::xdg_positioner::gravity gravityFromEdge(Qt::Edges edges) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h index cb81ed6aed..b66cedcfe6 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h @@ -64,6 +64,8 @@ public: bool isAlertState() const override { return m_alertState; } QString externWindowHandle() override; void setWindowPosition(const QPoint &position) override; + void setWindowSize(const QSize &size) override; + void setWindowGeometry(const QRect &rect) override; void setIcon(const QIcon &icon) override; void setSizeHints(); @@ -128,6 +130,8 @@ private: void resetConfiguration(); void grab(QWaylandInputDevice *seat, uint serial); + void reposition(); + void xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height) override; void xdg_popup_popup_done() override; void xdg_popup_repositioned(uint32_t token) override; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandcursor.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandcursor.cpp index 28f8d802eb..93509b92d9 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandcursor.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandcursor.cpp @@ -178,10 +178,6 @@ wl_cursor *QWaylandCursorTheme::requestCursor(WaylandCursor shape) ShapeAndName{shape, ""}, byShape); for (auto it = p.first; it != p.second; ++it) { if (wl_cursor *cursor = wl_cursor_theme_get_cursor(m_theme, it->name)) { - if (cursor->image_count == 0 || !cursor->images || !cursor->images[0]) { - qCWarning(lcQpaWayland) << "Ignoring empty Wayland cursor" << it->name; - continue; - } m_cursors[shape] = cursor; return cursor; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp index 5234cbb4d3..d0c396dc52 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddatacontrolv1.cpp @@ -150,7 +150,8 @@ void QWaylandDataControlSourceV1::zwlr_data_control_source_v1_send(const QString if (!content.isEmpty()) { // Create a sigpipe handler that does nothing, or clients may be forced to terminate // if the pipe is closed in the other end. - struct sigaction action, oldAction; + struct sigaction action = {}; + struct sigaction oldAction = {}; action.sa_handler = SIG_IGN; sigemptyset (&action.sa_mask); action.sa_flags = 0; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index 0fc97f4a61..8475d74737 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -226,10 +226,6 @@ void QWaylandInputDevice::Pointer::updateCursorTheme() return; // A warning has already been printed in loadCursorTheme if (auto *arrow = mCursor.theme->cursor(Qt::ArrowCursor)) { - if (arrow->image_count == 0 || !arrow->images || !arrow->images[0]) { - qCWarning(lcQpaWayland) << "Cursor theme returned an empty arrow cursor"; - return; - } int arrowPixelSize = qMax(arrow->images[0]->width, arrow->images[0]->height); // Not all cursor themes are square while (scale > 1 && arrowPixelSize / scale < cursorSize.width()) --scale; @@ -284,16 +280,8 @@ void QWaylandInputDevice::Pointer::updateCursor() const uint time = timer.isValid() ? timer.elapsed() : 0; if (struct ::wl_cursor *waylandCursor = mCursor.theme->cursor(shape)) { - if (waylandCursor->image_count == 0 || !waylandCursor->images) { - qCWarning(lcQpaWayland) << "Cursor theme returned an empty tablet cursor" << shape; - return; - } uint duration = 0; int frame = wl_cursor_frame_and_duration(waylandCursor, time, &duration); - if (frame < 0 || uint(frame) >= waylandCursor->image_count || !waylandCursor->images[frame]) { - qCWarning(lcQpaWayland) << "Cursor theme returned an invalid tablet cursor frame" << shape << frame; - return; - } ::wl_cursor_image *image = waylandCursor->images[frame]; struct wl_buffer *buffer = wl_cursor_image_get_buffer(image); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration.cpp index 8b6ac93571..0f473245f6 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -155,7 +155,7 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons return new QWaylandShmWindow(window, mDisplay.data()); } -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && QT_CONFIG(egl) QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { if (mDisplay->clientBufferIntegration()) diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration_p.h index 7d77539bd4..f54bd1dcd5 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandintegration_p.h @@ -40,7 +40,7 @@ class QWaylandPlatformServices; class QWaylandSessionManager; class Q_WAYLANDCLIENT_EXPORT QWaylandIntegration : public QPlatformIntegration -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && QT_CONFIG(egl) , public QNativeInterface::Private::QEGLIntegration #endif { @@ -54,7 +54,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; -#if QT_CONFIG(opengl) +#if QT_CONFIG(opengl) && QT_CONFIG(egl) QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; QOpenGLContext *createOpenGLContext(EGLContext context, EGLDisplay display, QOpenGLContext *shareContext) const override; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h index 047f591995..804d2f6fcb 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsessionmanager_p.h @@ -16,6 +16,8 @@ // We mean it. // +#include + #ifndef QT_NO_SESSIONMANAGER #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsurface.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsurface.cpp index bd7c358e42..ffccbefe61 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsurface.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylandsurface.cpp @@ -56,8 +56,10 @@ void QWaylandSurface::handleScreenRemoved(QScreen *qScreen) void QWaylandSurface::surface_enter(wl_output *output) { - auto addedScreen = QWaylandScreen::fromWlOutput(output); + if (!output) + return; + auto addedScreen = QWaylandScreen::fromWlOutput(output); if (!addedScreen) return; @@ -76,8 +78,10 @@ void QWaylandSurface::surface_enter(wl_output *output) void QWaylandSurface::surface_leave(wl_output *output) { - auto *removedScreen = QWaylandScreen::fromWlOutput(output); + if (!output) + return; + auto *removedScreen = QWaylandScreen::fromWlOutput(output); if (!removedScreen) return; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.cpp index 0726ca54ae..e9ad08d6a7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -617,6 +617,14 @@ void QWindowsKeyMapper::changeKeyboard() && (LCIDFontSig[7] & wchar_t(0x0800))) bidi = true; + WCHAR buffer[KL_NAMELENGTH]; + if (GetKeyboardLayoutName(buffer)) { + // https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values + QString newKLID = QString::fromStdWString(buffer); + m_isHebrewLayout = newKLID.endsWith(QLatin1String("40D"), Qt::CaseInsensitive); + } else + m_isHebrewLayout = false; + keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; m_seenAltGr = false; } @@ -701,8 +709,9 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32 quint32 fallbackKey = winceKeyBend(vk_key); if (!fallbackKey || fallbackKey == Qt::Key_unknown) { fallbackKey = 0; - if (vk_key != keyLayout[vk_key].qtKey[0] && vk_key != keyLayout[vk_key].qtKey[1] - && vk_key < 0x5B && vk_key > 0x2F) + if (vk_key != keyLayout[vk_key].qtKey[0] + && (vk_key != keyLayout[vk_key].qtKey[1] || m_isHebrewLayout) + && (vk_key < 0x5B && vk_key > 0x2F)) fallbackKey = vk_key; } keyLayout[vk_key].qtKey[8] = fallbackKey; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.h index 110d922024..9d0630acf7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowskeymapper.h @@ -78,7 +78,7 @@ private: KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; bool m_detectAltGrModifier = false; bool m_seenAltGr = false; - + bool m_isHebrewLayout = false; }; enum WindowsNativeModifiers { diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.cpp index c38cf4b79e..6adf3c9592 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -339,10 +339,6 @@ void QWindowsPointerHandler::handleCaptureRelease(QWindow *window, platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); qCDebug(lcQpaEvents) << "Automatic mouse capture " << window; - // Implement "Click to focus" for native child windows (unless it is a native widget window). - if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) - window->requestActivate(); - } else if (platformWindow->hasMouseCapture() && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture) && eventType == QEvent::MouseButtonRelease @@ -421,6 +417,27 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window, m_previousCaptureWindow = hasCapture ? window : nullptr; } +void QWindowsPointerHandler::handleWindowActivation(QWindow *window, + QEvent::Type eventType) +{ + if (eventType != QEvent::MouseButtonPress) + return; + + auto *focusWindow = QGuiApplication::focusWindow(); + if (window->isTopLevel()) { + // Windows does not send WM_MOUSEACTIVATE to an already-active top-level, + // so if focus currently sits in an embedded descendant (e.g. a native + // child window hosted via WindowContainer) we have to activate the + // top-level ourselves on mouse press. + if (focusWindow && window->isAncestorOf(focusWindow)) + window->requestActivate(); + } else if (!window->inherits("QWidgetWindow") && focusWindow != window) { + // "Click to focus" for native child windows. Skip QWidgetWindow, which + // handles focus at the widget level. + window->requestActivate(); + } +} + bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, quint32 count) @@ -859,6 +876,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, return true; } + handleWindowActivation(window, mouseEvent.type); handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); handleEnterLeave(window, currentWindowUnderPointer, globalPos); diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.h b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.h index afc9e4575c..0915cf93bd 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -47,6 +47,7 @@ private: bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers); void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons); void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos); + void handleWindowActivation(QWindow *window, QEvent::Type eventType); #if QT_CONFIG(tabletevent) QPointingDevicePtr findTabletDevice(QPointingDevice::PointerType pointerType) const; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowsscreen.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowsscreen.cpp index 597c19bff5..acbc93acfd 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -163,12 +162,14 @@ static void setMonitorDataFromSetupApi(QWindowsScreenData &data, // The first element in the clone group is the main monitor. deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId; deviceName.header.id = pathGroup[0].targetInfo.id; - if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) { + const LONG result = DisplayConfigGetDeviceInfo(&deviceName.header); + if (result == ERROR_SUCCESS) { data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath); } else { - qCWarning(lcQpaScreen) + // This can fail for virtual screens or disconnected displays - not an error + qCDebug(lcQpaScreen) << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id) - << QSystemError::windowsString(); + << QSystemError::windowsString(result); } } @@ -184,10 +185,12 @@ static void setMonitorDataFromSetupApi(QWindowsScreenData &data, deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME); deviceName.header.adapterId = path.targetInfo.adapterId; deviceName.header.id = path.targetInfo.id; - if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) { - qCWarning(lcQpaScreen) + const LONG result = DisplayConfigGetDeviceInfo(&deviceName.header); + if (result != ERROR_SUCCESS) { + // This can fail for virtual screens (WinDisc) or disconnected displays - not an error + qCDebug(lcQpaScreen) << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id) - << QSystemError::windowsString(); + << QSystemError::windowsString(result); continue; } @@ -206,7 +209,8 @@ static void setMonitorDataFromSetupApi(QWindowsScreenData &data, if (!SetupDiOpenDeviceInterfaceW(devInfo.get(), deviceName.monitorDevicePath, DIODI_NO_ADD, &deviceInterfaceData)) { - qCWarning(lcQpaScreen) + // This can fail for virtual screens with no physical target - not an error + qCDebug(lcQpaScreen) << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName) << QSystemError::windowsString(); continue; diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowstheme.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowstheme.cpp index fb45d2d94f..ab3d5c7cc7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowstheme.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowswindow.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowswindow.cpp index a609ac6c8a..1d86c40eff 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2071,7 +2071,14 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) // Force toplevel state as QWindow::isTopLevel cannot be relied upon here. if (wasTopLevel != isTopLevel) { setDropSiteEnabled(false); - setWindowFlags_sys(window()->flags(), unsigned(isTopLevel ? WindowCreationData::ForceTopLevel : WindowCreationData::ForceChild)); + m_data = setWindowFlags_sys(window()->flags(), unsigned(isTopLevel ? WindowCreationData::ForceTopLevel : WindowCreationData::ForceChild)); + // Update frame margins for the new top-level state. + // Child windows have no frame/titlebar, so margins must be zero. + // Top-level windows need frame margins recalculated. + if (isTopLevel) + updateFullFrameMargins(); + else + m_data.fullFrameMargins = {}; updateDropSite(isTopLevel); } } @@ -2345,6 +2352,7 @@ void QWindowsWindow::handleResized(int wParam, LPARAM lParam) return; case SIZE_MAXIMIZED: handleGeometryChange(); + updateRestoreGeometry(); // we might be in ResizeMoveActive mode but changed the screen if (!testFlag(WithinSetStyle) && !testFlag(WithinSetGeometry)) handleWindowStateChange(Qt::WindowMaximized | (isFullScreen_sys() ? Qt::WindowFullScreen : Qt::WindowNoState)); @@ -2397,8 +2405,8 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode, const RECT *su void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; - m_data.geometry = geometry_sys(); updateFullFrameMargins(); + m_data.geometry = geometry_sys(); QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE // which we no longer support in Qt 6) do not receive expose diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbconnection_screens.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbconnection_screens.cpp index b672e25365..e68d413422 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbconnection_screens.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbconnection_screens.cpp @@ -6,7 +6,6 @@ #include "qxcbscreen.h" #include "qxcbintegration.h" -#include #include #include diff --git a/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbscreen.cpp b/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbscreen.cpp index f6dbe8c189..2df919a8ac 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -16,7 +16,6 @@ #include #include -#include QT_BEGIN_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/.cmake.conf b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/.cmake.conf index be788d10f8..3c56bae820 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/.cmake.conf +++ b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/.cmake.conf @@ -1 +1 @@ -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.11.1") diff --git a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/CMakeLists.txt index 07520b4e21..f8e911b998 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/CMakeLists.txt @@ -2,7 +2,12 @@ # SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 3.16) -if(NOT PROJECT_NAME STREQUAL "QtBase" AND NOT PROJECT_NAME STREQUAL "Qt") + +# Read by _qt_internal_should_include_targets via qt_internal_add_plugin. +set(QT_PARENT_PROJECT_NAME "QtBase") +set(QT_STANDALONE_PROJECT_NAME "QSQLiteDriverPlugins") + +if(NOT PROJECT_NAME STREQUAL "${QT_PARENT_PROJECT_NAME}" AND NOT PROJECT_NAME STREQUAL "Qt") include(.cmake.conf) # Store initial build type (if any is specified) to be read by # qt_internal_set_cmake_build_type(). @@ -12,7 +17,7 @@ if(NOT PROJECT_NAME STREQUAL "QtBase" AND NOT PROJECT_NAME STREQUAL "Qt") "${CMAKE_BUILD_TYPE}") endif() - project(QSQLiteDriverPlugins + project("${QT_STANDALONE_PROJECT_NAME}" VERSION "${QT_REPO_MODULE_VERSION}" DESCRIPTION "Qt6 SQL driver plugins" HOMEPAGE_URL "https://qt.io/" @@ -78,6 +83,6 @@ if(QT_FEATURE_sql_mimer) add_subdirectory(mimer) endif() -if(NOT PROJECT_NAME STREQUAL "QtBase" AND NOT PROJECT_NAME STREQUAL "Qt") +if(NOT PROJECT_NAME STREQUAL "${QT_PARENT_PROJECT_NAME}" AND NOT PROJECT_NAME STREQUAL "Qt") qt_build_repo_end() endif() diff --git a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp index 7b1a657726..3cf5d3261a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp @@ -46,18 +46,16 @@ using namespace Qt::StringLiterals; static int qGetColumnType(const QString &tpName) { - const QString typeName = tpName.toLower(); - - if (typeName == "integer"_L1 || typeName == "int"_L1) + if (tpName.compare("integer"_L1, Qt::CaseInsensitive) == 0 || tpName.compare("int"_L1, Qt::CaseInsensitive) == 0) return QMetaType::Int; - if (typeName == "double"_L1 - || typeName == "float"_L1 - || typeName == "real"_L1 - || typeName.startsWith("numeric"_L1)) + if (tpName.compare("double"_L1, Qt::CaseInsensitive) == 0 + || tpName.compare("float"_L1, Qt::CaseInsensitive) == 0 + || tpName.compare("real"_L1, Qt::CaseInsensitive) == 0 + || tpName.startsWith("numeric"_L1, Qt::CaseInsensitive)) return QMetaType::Double; - if (typeName == "blob"_L1) + if (tpName.compare("blob"_L1, Qt::CaseInsensitive) == 0) return QMetaType::QByteArray; - if (typeName == "boolean"_L1 || typeName == "bool"_L1) + if (tpName.compare("boolean"_L1, Qt::CaseInsensitive) == 0 || tpName.compare("bool"_L1, Qt::CaseInsensitive) == 0) return QMetaType::Bool; return QMetaType::QString; } diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle.cpp b/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle.cpp index f20498cb67..3c060ccd37 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle.cpp @@ -31,7 +31,6 @@ QAndroidStyle::QAndroidStyle() : QFusionStyle() { QPixmapCache::clear(); - checkBoxControl = NULL; QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); QPalette *standardPalette = reinterpret_cast(nativeInterface->nativeResourceForIntegration("AndroidStandardPalette")); if (standardPalette) @@ -65,8 +64,8 @@ QAndroidStyle::QAndroidStyle() switch (itemType) { case QC_Checkbox: - checkBoxControl = new AndroidCompoundButtonControl(item.toVariantMap(), itemType); - m_androidControlsHash[int(itemType)] = checkBoxControl; + m_checkBoxControl = new AndroidCompoundButtonControl(item.toVariantMap(), itemType); + m_androidControlsHash[int(itemType)] = m_checkBoxControl; break; case QC_RadioButton: m_androidControlsHash[int(itemType)] = new AndroidCompoundButtonControl(item.toVariantMap(), @@ -375,6 +374,10 @@ void QAndroidStyle::drawComplexControl(ComplexControl cc, return; } if (cc == CC_GroupBox) { + if (!m_checkBoxControl) { + QFusionStyle::drawComplexControl(cc, opt, p, widget); + return; + } if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { // Draw frame QRect textRect = subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel, widget); @@ -432,7 +435,7 @@ void QAndroidStyle::drawComplexControl(ComplexControl cc, QStyleOptionButton box; box.QStyleOption::operator=(*groupBox); box.rect = checkBoxRect; - checkBoxControl->drawControl(&box, p, widget); + m_checkBoxControl->drawControl(&box, p, widget); } } return; @@ -475,6 +478,9 @@ QRect QAndroidStyle::subControlRect(ComplexControl cc, SubControl sc, const QWidget *widget) const { + if (cc == CC_GroupBox && !m_checkBoxControl) + return QFusionStyle::subControlRect(cc, opt, sc, widget); + const ItemType itemType = qtControl(cc); AndroidControlsHash::const_iterator it = itemType != QC_UnknownType ? m_androidControlsHash.find(itemType) @@ -486,7 +492,7 @@ QRect QAndroidStyle::subControlRect(ComplexControl cc, case CC_GroupBox: { if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { QSize textSize = opt->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); - QSize checkBoxSize = checkBoxControl->size(opt); + QSize checkBoxSize = m_checkBoxControl->size(opt); int indicatorWidth = checkBoxSize.width(); int indicatorHeight = checkBoxSize.height(); QRect checkBoxRect; @@ -543,9 +549,13 @@ int QAndroidStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, case PM_ScrollBarExtent: return 0; case PM_IndicatorWidth: - return checkBoxControl->size(option).width(); + if (m_checkBoxControl) + return m_checkBoxControl->size(option).width(); + return QFusionStyle::pixelMetric(metric, option, widget); case PM_IndicatorHeight: - return checkBoxControl->size(option).height(); + if (m_checkBoxControl) + return m_checkBoxControl->size(option).height(); + return QFusionStyle::pixelMetric(metric, option, widget); default: return QFusionStyle::pixelMetric(metric, option, widget); } @@ -562,7 +572,7 @@ QSize QAndroidStyle::sizeFromContents(ContentsType ct, if (const QStyleOptionHeader *hdr = qstyleoption_cast(opt)) { bool nullIcon = hdr->icon.isNull(); int margin = pixelMetric(QStyle::PM_HeaderMargin, hdr, w); - int iconSize = nullIcon ? 0 : checkBoxControl->size(opt).width(); + int iconSize = nullIcon ? 0 : pixelMetric(QStyle::PM_IndicatorWidth, opt, w); QSize txt; /* * These next 4 lines are a bad hack to fix a bug in case a QStyleSheet is applied at QApplication level. @@ -593,10 +603,10 @@ QSize QAndroidStyle::sizeFromContents(ContentsType ct, : m_androidControlsHash.end(); if (it != m_androidControlsHash.end()) return it.value()->sizeFromContents(opt, sz, w); - if (ct == CT_GroupBox) { + if (ct == CT_GroupBox && m_checkBoxControl) { if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { QSize textSize = opt->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); - QSize checkBoxSize = checkBoxControl->size(opt); + QSize checkBoxSize = m_checkBoxControl->size(opt); int indicatorWidth = checkBoxSize.width(); int indicatorHeight = checkBoxSize.height(); QRect checkBoxRect; diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle_p.h b/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle_p.h index 3b9cf6aa1a..bbaf2d1b7a 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/android/qandroidstyle_p.h @@ -348,7 +348,7 @@ private: typedef QHash AndroidControlsHash; AndroidControlsHash m_androidControlsHash; QPalette m_standardPalette; - AndroidCompoundButtonControl *checkBoxControl; + AndroidCompoundButtonControl *m_checkBoxControl = nullptr; }; QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac.mm b/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac.mm index 0b05a31ca5..5d980d29e0 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac.mm @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -3188,6 +3189,21 @@ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOpt return icon.pixmap(QSize(size, size), dpr); } +QIcon QMacStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, + const QWidget *widget) const +{ + switch (standardIcon) { + case SP_ToolBarHorizontalExtensionButton: + return QAppleIconEngine::fromTheme("chevron.forward.2"); + case SP_ToolBarVerticalExtensionButton: + return QAppleIconEngine::fromTheme("chevron.down.2"); + default: + break; + } + + return QCommonStyle::standardIcon(standardIcon, option, widget); +} + void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p, const QWidget *w) const { @@ -4379,8 +4395,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter myTab.palette.setColor(foregroundRole, Qt::white); if (myTab.documentMode && isDarkMode()) { - bool active = (myTab.state & State_Selected) && (myTab.state & State_Active); - myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray); + if (const auto *tabBar = qobject_cast(w)) { + if (!tabBar->tabTextColor(myTab.tabIndex).isValid()) { + bool active = (myTab.state & State_Selected) && (myTab.state & State_Active); + myTab.palette.setColor(foregroundRole, active ? Qt::white : Qt::gray); + } + } } int heightOffset = 0; diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac_p.h b/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac_p.h index 078e8894a3..56918aec7b 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/mac/qmacstyle_mac_p.h @@ -68,6 +68,9 @@ public: QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt, const QWidget *widget = nullptr) const; + QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option, + const QWidget *widget) const; + QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const; diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style.cpp b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style.cpp index cf97071504..f80d9f57b8 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -68,6 +68,10 @@ inline bool isPressed(const QStyleOption *option) { return option->state.testFlag(QStyle::State_Sunken); } +inline bool isSelected(const QStyleOption *option) +{ + return option->state.testFlag(QStyle::State_Selected); +} inline bool isHover(const QStyleOption *option) { return option->state.testFlag(QStyle::State_MouseOver); @@ -438,8 +442,10 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt if (sb->frame && (sub & SC_SpinBoxFrame)) drawLineEditFrame(cp.painter(), frameRect, option); - const auto drawUpDown = [&](QStyle::SubControl sc) { - const bool isEnabled = state & QStyle::State_Enabled; + const auto drawUpDown = [&](QStyle::SubControl sc, + QAbstractSpinBox::StepEnabledFlag flag) { + const bool isEnabled = + state.testFlag(QStyle::State_Enabled) && sb->stepEnabled.testFlag(flag); const bool isUp = sc == SC_SpinBoxUp; const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget); if (isEnabled && sb->activeSubControls & sc) @@ -447,12 +453,15 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt winUI3Color(subtleHighlightColor)); cp->setFont(d->assetFont); - cp->setPen(sb->palette.buttonText().color()); + cp->setPen(sb->palette.color(isEnabled ? QPalette::Active : QPalette::Disabled, + QPalette::ButtonText)); cp->setBrush(Qt::NoBrush); cp->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown)); }; - if (sub & SC_SpinBoxUp) drawUpDown(SC_SpinBoxUp); - if (sub & SC_SpinBoxDown) drawUpDown(SC_SpinBoxDown); + if (sub & SC_SpinBoxUp) + drawUpDown(SC_SpinBoxUp, QAbstractSpinBox::StepUpEnabled); + if (sub & SC_SpinBoxDown) + drawUpDown(SC_SpinBoxDown, QAbstractSpinBox::StepDownEnabled); if (state & State_KeyboardFocusChange && state & State_HasFocus) { QStyleOptionFocusRect fropt; fropt.QStyleOption::operator=(*option); @@ -817,7 +826,6 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt QStyleOptionToolButton label = *toolbutton; label.state = bflags; label.rect = buttonRect.marginsRemoved(QMargins(fw, fw, fw, fw)); - prx->drawControl(CE_ToolButtonLabel, &label, painter, widget); if (toolbutton->subControls.testFlag(SC_ToolButtonMenu)) { QPainterStateGuard psg(painter); @@ -834,15 +842,18 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt painter->drawText(textRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed)); } else if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) { - const int mbi = prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget); + const int mbi = qRound(prx->pixelMetric(PM_MenuButtonIndicator, toolbutton, widget) * 0.3); const QRect &ir = toolbutton->rect; - QRect rect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6 - fw, - mbi - 6); + QRect rect(ir.right() - mbi - 2 * fw, ir.bottom() - mbi - fw, mbi, + mbi); rect = visualRect(toolbutton->direction, buttonRect, rect); + const QRect lblRect = label.rect - QMargins(0, 0, rect.width(), 0); + label.rect = visualRect(toolbutton->direction, buttonRect, lblRect); painter->setFont(QFont(d->assetFont)); painter->setPen(controlTextColor(option)); painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed)); } + prx->drawControl(CE_ToolButtonLabel, &label, painter, widget); } break; #endif // QT_CONFIG(toolbutton) @@ -997,7 +1008,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption if (indicator != QStyleOptionHeader::None) { QPainterStateGuard psg(painter); QFont f(d->assetFont); - f.setPointSize(6); + f.setPointSize(option->rect.height()); painter->setFont(f); painter->setPen(header->palette.text().color()); const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown @@ -1083,10 +1094,10 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption case PE_PanelButtonBevel:{ const bool isEnabled = state & QStyle::State_Enabled; const bool isMouseOver = state & QStyle::State_MouseOver; - const bool isRaised = state & QStyle::State_Raised; + const bool isAutoRaise = state & QStyle::State_AutoRaise; const int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget); const QRectF rect = option->rect.marginsRemoved(QMargins(fw, fw, fw, fw)); - if (element == PE_PanelButtonTool && ((!isMouseOver && !isRaised) || !isEnabled)) + if (element == PE_PanelButtonTool && ((!isMouseOver && isAutoRaise) || !isEnabled)) painter->setPen(Qt::NoPen); else painter->setPen(winUI3Color(controlStrokePrimary)); @@ -1499,35 +1510,29 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op painter->setFont(toolbutton->font); QRect pr = rect, tr = rect; - int alignment = Qt::TextShowMnemonic; + int alignment = Qt::TextShowMnemonic | Qt::AlignCenter; if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget)) alignment |= Qt::TextHideMnemonic; if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) { pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(0, pr.height() - 1, 0, -1); - pr.translate(shiftX, shiftY); - if (!hasArrow) { - proxy()->drawItemPixmap(painter, pr, Qt::AlignCenter, pm); - } else { - drawArrow(proxy(), toolbutton, pr, painter, widget); - } - alignment |= Qt::AlignCenter; } else { pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint() tr.adjust(pr.width(), 0, 0, 0); - pr.translate(shiftX, shiftY); - if (!hasArrow) { - proxy()->drawItemPixmap(painter, QStyle::visualRect(toolbutton->direction, rect, pr), Qt::AlignCenter, pm); - } else { - drawArrow(proxy(), toolbutton, pr, painter, widget); - } - alignment |= Qt::AlignLeft | Qt::AlignVCenter; + } + pr.translate(shiftX, shiftY); + if (hasArrow) { + drawArrow(proxy(), toolbutton, pr, painter, widget); + } else { + const auto vr = QStyle::visualRect(toolbutton->direction, rect, pr); + proxy()->drawItemPixmap(painter, vr, Qt::AlignCenter, pm); } tr.translate(shiftX, shiftY); - const QString text = d->toolButtonElideText(toolbutton, tr, alignment); painter->setPen(controlTextColor(option)); - proxy()->drawItemText(painter, QStyle::visualRect(toolbutton->direction, rect, tr), alignment, toolbutton->palette, + const QString text = d->toolButtonElideText(toolbutton, tr, alignment); + const auto vr = QStyle::visualRect(toolbutton->direction, rect, tr); + proxy()->drawItemText(painter, vr, alignment, toolbutton->palette, toolbutton->state & State_Enabled, text); } else { rect.translate(shiftX, shiftY); @@ -1775,18 +1780,29 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op case CE_MenuItem: if (const auto *menuitem = qstyleoption_cast(option)) { + using namespace StyleOptionHelper; + const auto visualMenuRect = [&](const QRect &rect) { return visualRect(option->direction, menuitem->rect, rect); }; - bool dis = !(menuitem->state & State_Enabled); - bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable - ? menuitem->checked : false; - bool act = menuitem->state & State_Selected; + + const bool checked = + menuitem->checkType != QStyleOptionMenuItem::NotCheckable && menuitem->checked; const QRect rect = menuitem->rect.marginsRemoved(QMargins(2,2,2,2)); - if (act && dis == false) { - drawRoundedRect(painter, rect, Qt::NoPen, highContrastTheme ? menuitem->palette.brush(QPalette::Highlight) - : QBrush(winUI3Color(subtleHighlightColor))); + if (!isDisabled(menuitem)) { + QPen pen(Qt::NoPen); + QBrush brush(Qt::NoBrush); + if (highContrastTheme) { + pen = QPen(menuitem->palette.highlight().color(), 2); + brush = menuitem->palette.window(); + } else if (isPressed(menuitem)) { + brush = winUI3Color(subtlePressedColor); + } else if (isSelected(menuitem)) { // == hover + brush = winUI3Color(subtleHighlightColor); + } + if (pen != Qt::NoPen || brush != Qt::NoBrush) + drawRoundedRect(painter, rect, pen, brush); } if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) { constexpr int yoff = 1; @@ -1815,9 +1831,9 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op rect.y(), menuitem->maxIconWidth - 4, rect.height()))); - QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; - if (act && !dis) - mode = QIcon::Active; + const auto mode = isDisabled(menuitem) + ? QIcon::Disabled + : (isSelected(menuitem) ? QIcon::Active : QIcon::Normal); const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget); QRect pmr(QPoint(0, 0), QSize(size, size)); pmr.moveCenter(vRect.center()); @@ -1837,10 +1853,12 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op QColor penColor; if (highContrastTheme) { - penColor = menuitem->palette.color(act ? QPalette::HighlightedText - : QPalette::Text); + penColor = menuitem->palette.color( + isSelected(menuitem) ? QPalette::HighlightedText : QPalette::Text); } else { - penColor = controlTextColor(option); + QStyleOption tmpOpt(*option); + tmpOpt.state.setFlag(State_Sunken, false); + penColor = controlTextColor(&tmpOpt); } painter->setPen(penColor); @@ -2055,6 +2073,8 @@ int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt, return Qt::LeftButton; case QStyle::SH_Slider_PageSetButtons: return 0; + case SH_SpinControls_DisableOnBounds: + return 1; default: return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData); } @@ -2176,10 +2196,23 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp } break; #endif // QT_CONFIG(toolbar) - case QStyle::SE_HeaderLabel: - case QStyle::SE_HeaderArrow: - ret = QWindowsVistaStyle::subElementRect(element, option, widget); + case SE_HeaderLabel: { + const int margin = proxy()->pixelMetric(PM_HeaderMargin, option, widget); + ret = option->rect.marginsRemoved({ margin, margin, margin, margin }); break; + } + case SE_HeaderArrow: { + ret = option->rect; + if (const auto *header = qstyleoption_cast(option)) { + // the sort indicator is always show above in the win11 style + if (header->sortIndicator != QStyleOptionHeader::None) { + const int arrowSize = proxy()->pixelMetric(PM_HeaderMarkSize, option, widget); + const int xCenter = ret.center().x(); + ret = QRect(xCenter - arrowSize / 2, ret.top(), arrowSize, arrowSize); + } + } + break; + } case SE_PushButtonContents: { int border = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget); ret = option->rect.marginsRemoved(QMargins(border, border, border, border)); @@ -2541,14 +2574,20 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o break; } case CT_ToolButton: { - contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); - // we want our own horizontal spacing - const int oldMargin = proxy()->pixelMetric(PM_ButtonMargin, option, widget); - contentSize.rwidth() += 2 * contentHMargin - oldMargin; - if (const auto toolbutton = qstyleoption_cast(option)) { - if (toolbutton->features.testFlag(QStyleOptionToolButton::HasMenu)) - contentSize.rwidth() += size.height(); + contentSize = size; + if (const auto tb = qstyleoption_cast(option)) { + // no separate menu, only dropdown icon + if (!tb->subControls.testFlag(SC_ToolButtonMenu)) { + if (tb->features.testFlag(QStyleOptionToolButton::HasMenu)) + contentSize.rwidth() += 2; + } + if (tb->toolButtonStyle == Qt::ToolButtonTextBesideIcon + || tb->toolButtonStyle == Qt::ToolButtonIconOnly) { + contentSize.rheight() = qMax(contentSize.height(), tb->iconSize.height() + 4); + } } + const auto fw = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget); + contentSize += QSize(contentHMargin + 2 * fw, 2 * fw); break; } case CT_ItemViewItem: { @@ -2674,6 +2713,9 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, case PM_ProgressBarChunkWidth: res = 0; // no chunks on windows11 break; + case PM_HeaderMarkSize: + res = 6; + break; default: res = QWindowsVistaStyle::pixelMetric(metric, option, widget); } @@ -2848,7 +2890,8 @@ void QWindows11Style::dwmSetWindowCornerPreference(const QWidget *widget, bool b static constexpr auto dwmcpRoundSmall = 3; static constexpr auto dwmcpDefault = 0; #endif - if (widget && widget->isWindow() && widget->testAttribute(Qt::WA_WState_Created)) { + if (widget && widget->isWindow() && widget->testAttribute(Qt::WA_WState_Created) + && !widget->windowFlags().testFlag(Qt::FramelessWindowHint)) { const auto window = widget->windowHandle(); if (window && window->handle()) { const auto wId = reinterpret_cast(widget->winId()); @@ -3018,12 +3061,29 @@ QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon, return getIcon(Icon::More, 1.0); case SP_TabCloseButton: return getIcon(Icon::ChromeClose, 0.6); + case SP_ArrowUp: + return getIcon(Icon::ChevronUpMed, 1.0); + case SP_ArrowDown: + return getIcon(Icon::ChevronDownMed, 1.0); + case SP_ArrowLeft: + return getIcon(Icon::ChevronLeftMed, 1.0); + case SP_ArrowRight: + return getIcon(Icon::ChevronRightMed, 1.0); default: break; } return QWindowsVistaStyle::standardIcon(standardIcon, option, widget); } +QPixmap QWindows11Style::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, + const QStyleOption *option) const +{ + if (iconMode == QIcon::Disabled) + return QWindowsVistaStyle::generatedIconPixmap(iconMode, pixmap, option); + return pixmap; +} + + QColor QWindows11Style::calculateAccentColor(const QStyleOption *option) const { using namespace StyleOptionHelper; @@ -3063,7 +3123,7 @@ QBrush QWindows11Style::controlFillBrush(const QStyleOption *option, ControlType }; if (option->palette.isBrushSet(QPalette::Current, QPalette::Button)) - return option->palette.button(); + return option->palette.brush(QPalette::Current, QPalette::Button); if (!isChecked(option) && isAutoRaise(option)) return Qt::NoBrush; @@ -3082,7 +3142,7 @@ QBrush QWindows11Style::inputFillBrush(const QStyleOption *option, const QWidget using namespace StyleOptionHelper; const auto role = widget ? widget->backgroundRole() : QPalette::Window; if (option->palette.isBrushSet(QPalette::Current, role)) - return option->palette.button(); + return option->palette.brush(QPalette::Current, role); if (isDisabled(option)) return winUI3Color(fillControlDisabled); @@ -3104,7 +3164,7 @@ QColor QWindows11Style::controlTextColor(const QStyleOption *option, bool ignore }; if (option->palette.isBrushSet(QPalette::Current, QPalette::ButtonText)) - return option->palette.buttonText().color(); + return option->palette.color(QPalette::Current, QPalette::ButtonText); const int colorIndex = !ignoreIsChecked && isChecked(option) ? 1 : 0; const auto state = calcControlState(option); @@ -3123,15 +3183,20 @@ void QWindows11Style::drawLineEditFrame(QPainter *p, const QRectF &rect, const Q if (!isEditable || StyleOptionHelper::isDisabled(o)) return; - QPainterStateGuard psg(p); - p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 0.5, 0, -1))); const bool hasFocus = o->state & State_HasFocus; const auto underlineCol = hasFocus ? o->palette.color(QPalette::Accent) : colorSchemeIndex == 0 ? QColor(0x80, 0x80, 0x80) : QColor(0xa0, 0xa0, 0xa0); - const auto penUnderline = QPen(underlineCol, hasFocus ? 2 : 1); - drawRoundedRect(p, rect, penUnderline, Qt::NoBrush); + QPainterStateGuard psg(p); + if (hasFocus) { + p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 1.5, 0, -1))); + const QRectF r(rect.top(), rect.left(), rect.width(), rect.height() - 1); + drawRoundedRect(p, r, QPen(underlineCol, 2), Qt::NoBrush); + } else { + p->setClipRect(rect.marginsRemoved(QMarginsF(0, rect.height() - 0.5, 0, -1))); + drawRoundedRect(p, rect, underlineCol, Qt::NoBrush); + } } QColor QWindows11Style::winUI3Color(enum WINUI3Color col) const diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style_p.h b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style_p.h index 9955f6d655..b9ba3041f7 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -121,6 +121,8 @@ public: void polish(QApplication *app) override; void unpolish(QApplication *app) override; bool eventFilter(QObject *obj, QEvent *event) override; + QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, + const QStyleOption *option) const override; protected: QWindows11Style(QWindows11StylePrivate &dd); diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsthemedata_p.h b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsthemedata_p.h index 789a15e8bc..ba07702465 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsthemedata_p.h +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsthemedata_p.h @@ -17,9 +17,13 @@ // #include + +#include #include + #include #include + #include @@ -104,11 +108,10 @@ struct ThemeMapKey { : theme(data.theme), partId(data.partId), stateId(data.stateId), noBorder(data.noBorder), noContent(data.noContent) {} + friend size_t qHash(const ThemeMapKey &key, size_t seed = 0) noexcept + { return qHashMulti(seed, key.theme, key.partId, key.stateId); } }; -inline size_t qHash(const ThemeMapKey &key) -{ return key.theme ^ key.partId ^ key.stateId; } - inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2) { return k1.theme == k2.theme diff --git a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index 531abdeba3..2d8eae7d20 100644 --- a/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/local/recipes/qt/qtbase/source/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -80,10 +80,6 @@ static void qt_add_rect(HRGN &winRegion, QRect r) static HRGN qt_hrgn_from_qregion(const QRegion ®ion) { HRGN hRegion = CreateRectRgn(0,0,0,0); - if (region.rectCount() == 1) { - qt_add_rect(hRegion, region.boundingRect()); - return hRegion; - } for (const QRect &rect : region) qt_add_rect(hRegion, rect); return hRegion; @@ -2930,7 +2926,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption const auto size = proxy()->pixelMetric(PM_SmallIconSize, option, widget); QRect pmr(QPoint(0, 0), QSize(size, size)); pmr.moveCenter(vCheckRect.center()); - menuitem->icon.paint(painter, vCheckRect, Qt::AlignCenter, mode, + menuitem->icon.paint(painter, pmr, Qt::AlignCenter, mode, checked ? QIcon::On : QIcon::Off); } diff --git a/local/recipes/qt/qtbase/source/src/printsupport/platform/windows/qprintengine_win.cpp b/local/recipes/qt/qtbase/source/src/printsupport/platform/windows/qprintengine_win.cpp index 16cb95f888..d9e4787ffd 100644 --- a/local/recipes/qt/qtbase/source/src/printsupport/platform/windows/qprintengine_win.cpp +++ b/local/recipes/qt/qtbase/source/src/printsupport/platform/windows/qprintengine_win.cpp @@ -85,6 +85,7 @@ bool QWin32PrintEngine::begin(QPaintDevice *pdev) if (d->reinit) { d->resetDC(); d->reinit = false; + d->updateMetrics(); } // ### set default colors and stuff... @@ -191,6 +192,7 @@ bool QWin32PrintEngine::newPage() if (!d->resetDC()) return false; d->reinit = false; + d->updateMetrics(); } if (StartPage(d->hdc) <= 0) { @@ -994,6 +996,7 @@ void QWin32PrintEnginePrivate::doReinit() } else { resetDC(); reinit = false; + updateMetrics(); } } @@ -1642,6 +1645,7 @@ void QWin32PrintEnginePrivate::setPageSize(const QPageSize &pageSize) devMode->dmPaperWidth = 0; devMode->dmPaperLength = 0; } else { + has_custom_paper_size = true; devMode->dmPaperSize = DMPAPER_USER; devMode->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH; // Size in tenths of a millimeter @@ -1699,14 +1703,23 @@ void QWin32PrintEnginePrivate::updatePageLayout() void QWin32PrintEnginePrivate::updateMetrics() { m_paintRectPixels = m_pageLayout.paintRectPixels(resolution); - // Some print devices allow scaling, so that "virtual" page size != current paper size - const int devWidth = GetDeviceCaps(hdc, PHYSICALWIDTH); - const int devHeight = GetDeviceCaps(hdc, PHYSICALHEIGHT); - const int pageWidth = m_pageLayout.fullRectPixels(dpi_x).width(); - const int pageHeight = m_pageLayout.fullRectPixels(dpi_y).height(); - const qreal pageScaleX = (devWidth && pageWidth) ? qreal(devWidth) / pageWidth : 1; - const qreal pageScaleY = (devHeight && pageHeight) ? qreal(devHeight) / pageHeight : 1; - m_paintRectPixels = QTransform::fromScale(pageScaleX, pageScaleY).mapRect(m_paintRectPixels); + + qreal pageScaleX = 1; + qreal pageScaleY = 1; + + // Some print devices allow scaling, so that "virtual" page size != current paper size. + // Skip this scaling for custom page sizes, since the driver may not report the custom + // dimensions via GetDeviceCaps, which would incorrectly squash the paint rect to the + // default paper size (QTBUG-142745). + if (!has_custom_paper_size) { + const int devWidth = GetDeviceCaps(hdc, PHYSICALWIDTH); + const int devHeight = GetDeviceCaps(hdc, PHYSICALHEIGHT); + const int pageWidth = m_pageLayout.fullRectPixels(dpi_x).width(); + const int pageHeight = m_pageLayout.fullRectPixels(dpi_y).height(); + pageScaleX = (devWidth && pageWidth) ? qreal(devWidth) / pageWidth : 1; + pageScaleY = (devHeight && pageHeight) ? qreal(devHeight) / pageHeight : 1; + m_paintRectPixels = QTransform::fromScale(pageScaleX, pageScaleY).mapRect(m_paintRectPixels); + } QSizeF sizeMM = m_pageLayout.paintRect(QPageLayout::Millimeter).size(); m_paintSizeMM = QSize(qRound(sizeMM.width()), qRound(sizeMM.height())); diff --git a/local/recipes/qt/qtbase/source/src/sql/kernel/qsqlfield.cpp b/local/recipes/qt/qtbase/source/src/sql/kernel/qsqlfield.cpp index 25132f3429..c2b96f633b 100644 --- a/local/recipes/qt/qtbase/source/src/sql/kernel/qsqlfield.cpp +++ b/local/recipes/qt/qtbase/source/src/sql/kernel/qsqlfield.cpp @@ -543,11 +543,13 @@ QDebug operator<<(QDebug dbg, const QSqlField &f) If the value is auto-generated by the database, for example auto-increment primary key values, this value is \c true. - \note When using the ODBC driver, due to limitations in the ODBC API, - the \c isAutoValue() field is only populated in a QSqlField resulting from a - QSqlRecord obtained by executing a \c SELECT query. It is \c false in a QSqlField - resulting from a QSqlRecord returned from QSqlDatabase::record() or - QSqlDatabase::primaryIndex(). + \note When writing a new record to the database, an \c autoValue field will + only hold the new value generated by the database once the record has been + submitted to the database. When using the ODBC driver, due to limitations + in the ODBC API, the \c isAutoValue() field is only populated in a + QSqlField resulting from a QSqlRecord obtained by executing a \c SELECT + query. It is \c false for a QSqlField resulting from a QSqlRecord returned + from QSqlDatabase::record() or QSqlDatabase::primaryIndex(). */ /*! diff --git a/local/recipes/qt/qtbase/source/src/sql/models/qsqlrelationaltablemodel.cpp b/local/recipes/qt/qtbase/source/src/sql/models/qsqlrelationaltablemodel.cpp index c9d95ebdff..ed22cc71b2 100644 --- a/local/recipes/qt/qtbase/source/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/local/recipes/qt/qtbase/source/src/sql/models/qsqlrelationaltablemodel.cpp @@ -310,7 +310,9 @@ void QSqlRelationalTableModelPrivate::clearCache() \table \row \li \inlineimage noforeignkeys.png + {Table showing city and country as numeric foreign key values} \li \inlineimage foreignkeys.png + {Table showing city and country resolved to text strings} \endtable The screenshot on the left shows a plain QSqlTableModel in a diff --git a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake b/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake index 41a038a5d7..ea065b4ad7 100644 --- a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake +++ b/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake @@ -3,8 +3,6 @@ # # Original file location was Tests/RunCMake/CMakeLists.txt -set(RunCMakeDir ${CMAKE_CURRENT_LIST_DIR}) - macro(add_RunCMake_test test) set(TEST_ARGS ${ARGN}) if ("${ARGV1}" STREQUAL "TEST_DIR") @@ -23,12 +21,9 @@ macro(add_RunCMake_test test) if(NOT QT_RUN_CMAKE_SCRIPT_PATH) set(QT_RUN_CMAKE_SCRIPT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${Test_Dir}/RunCMakeTest.cmake") endif() - # Qt specific options - list(APPEND TEST_ARGS - -D_Qt6CTestMacros=${_Qt6CTestMacros} - ) - add_test(NAME RunCMake.${test} COMMAND ${CMAKE_COMMAND} - -DCMAKE_MODULE_PATH=${RunCMakeDir} + add_test(NAME RunCMake.${test} COMMAND ${CMAKE_CMAKE_COMMAND} + -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR} + -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig} -DRunCMake_GENERATOR=${CMAKE_GENERATOR} -DRunCMake_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE} diff --git a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0001-Make-RunCMake-compatible-with-downstream.patch b/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0001-Make-RunCMake-compatible-with-downstream.patch index cad76caf4c..a4a3a1e272 100644 --- a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0001-Make-RunCMake-compatible-with-downstream.patch +++ b/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0001-Make-RunCMake-compatible-with-downstream.patch @@ -1,33 +1,5 @@ Subject: [PATCH] Make RunCMake compatible with downstream projects --- -Index: src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake b/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake ---- a/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake (revision 5201a6f8063d7be8fee3d9cd01e7c5e195869467) -+++ b/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake (revision 27aa47b3c906dbe263f23ff4abbdb535b504404f) -@@ -3,6 +3,8 @@ - # - # Original file location was Tests/RunCMake/CMakeLists.txt - -+set(RunCMakeDir ${CMAKE_CURRENT_LIST_DIR}) -+ - macro(add_RunCMake_test test) - set(TEST_ARGS ${ARGN}) - if ("${ARGV1}" STREQUAL "TEST_DIR") -@@ -18,8 +20,8 @@ - if(CMAKE_C_COMPILER_ID STREQUAL "LCC") - list(APPEND TEST_ARGS -DRunCMake_TEST_LCC=1) - endif() -- add_test(NAME RunCMake.${test} COMMAND ${CMAKE_CMAKE_COMMAND} -- -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR} -+ add_test(NAME RunCMake.${test} COMMAND ${CMAKE_COMMAND} -+ -DCMAKE_MODULE_PATH=${RunCMakeDir} - -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig} - -DRunCMake_GENERATOR=${CMAKE_GENERATOR} - -DRunCMake_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE} Index: src/testinternal/3rdparty/cmake/RunCMake.cmake IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP diff --git a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0004-Propagate-_Qt6CTestMacros.patch b/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0004-Propagate-_Qt6CTestMacros.patch deleted file mode 100644 index d45c1e6ea7..0000000000 --- a/local/recipes/qt/qtbase/source/src/testinternal/3rdparty/cmake/patches/0004-Propagate-_Qt6CTestMacros.patch +++ /dev/null @@ -1,19 +0,0 @@ -Index: src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake b/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake ---- a/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake (revision b23da37d71bde4673fab3510596514e4ac451053) -+++ b/src/testinternal/3rdparty/cmake/QtRunCMakeTestHelpers.cmake (revision e71805860401b494ab3b6e1c12eaa1c84fd89994) -@@ -20,6 +20,10 @@ - if(CMAKE_C_COMPILER_ID STREQUAL "LCC") - list(APPEND TEST_ARGS -DRunCMake_TEST_LCC=1) - endif() -+ # Qt specific options -+ list(APPEND TEST_ARGS -+ -D_Qt6CTestMacros=${_Qt6CTestMacros} -+ ) - add_test(NAME RunCMake.${test} COMMAND ${CMAKE_COMMAND} - -DCMAKE_MODULE_PATH=${RunCMakeDir} - -DRunCMake_GENERATOR_IS_MULTI_CONFIG=${_isMultiConfig} diff --git a/local/recipes/qt/qtbase/source/src/testinternal/CMakeLists.txt b/local/recipes/qt/qtbase/source/src/testinternal/CMakeLists.txt index d35ccab1d0..edd8796c7e 100644 --- a/local/recipes/qt/qtbase/source/src/testinternal/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/src/testinternal/CMakeLists.txt @@ -28,8 +28,6 @@ qt_internal_add_module(TestInternalsPrivate 3rdparty/cmake/RunCMake.cmake QtRunCMakeTestWrappers.cmake QtRunCMake.cmake - # Temporary wrapper until the `include(RunCMake)` are changed to `include(QtRunCmake)` - RunCMake.cmake EXTRA_CMAKE_INCLUDES QtRunCMakeTestWrappers.cmake ) diff --git a/local/recipes/qt/qtbase/source/src/testinternal/QtRunCMakeTestWrappers.cmake b/local/recipes/qt/qtbase/source/src/testinternal/QtRunCMakeTestWrappers.cmake index cead9e52c8..087c96db99 100644 --- a/local/recipes/qt/qtbase/source/src/testinternal/QtRunCMakeTestWrappers.cmake +++ b/local/recipes/qt/qtbase/source/src/testinternal/QtRunCMakeTestWrappers.cmake @@ -8,8 +8,11 @@ function(qt_internal_add_RunCMake_test test) # Add the common Qt specific setups set(common_args "-DQt6_DIR=${Qt6_DIR}" + "-D_Qt6CTestMacros=${_Qt6CTestMacros}" "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_FUNCTION_LIST_DIR}" ) + # Set some compatibility variables that the original add_RunCMake_test expects + set(CMAKE_CMAKE_COMMAND "${CMAKE_COMMAND}") # Get test dir, like add_RunCMake_test does. if("${ARGV1}" STREQUAL "TEST_DIR") diff --git a/local/recipes/qt/qtbase/source/src/testinternal/RunCMake.cmake b/local/recipes/qt/qtbase/source/src/testinternal/RunCMake.cmake deleted file mode 100644 index 1419a0c09f..0000000000 --- a/local/recipes/qt/qtbase/source/src/testinternal/RunCMake.cmake +++ /dev/null @@ -1 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/QtRunCMake.cmake) diff --git a/local/recipes/qt/qtbase/source/src/testlib/qpropertytesthelper_p.h b/local/recipes/qt/qtbase/source/src/testlib/qpropertytesthelper_p.h index 6bdd1feda1..05ffca1bf2 100644 --- a/local/recipes/qt/qtbase/source/src/testlib/qpropertytesthelper_p.h +++ b/local/recipes/qt/qtbase/source/src/testlib/qpropertytesthelper_p.h @@ -141,19 +141,19 @@ void testReadWritePropertyBasics( const QMetaObject *metaObject = instance.metaObject(); QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName)); QVERIFY2(metaProperty.metaType() == QMetaType::fromType(), - QByteArray("Preconditions not met for ") + propertyName + "\n" + QByteArray{QByteArray("Preconditions not met for ") + propertyName + "\n" "The type of initial and changed value does not match the type of the property.\n" "Please ensure that the types match exactly (convertability is not enough).\n" "You can provide the template types to the " "function explicitly to force a certain type.\n" "Expected was a " + metaProperty.metaType().name() - + " but " + QMetaType::fromType().name() + " was provided."); + + " but " + QMetaType::fromType().name() + " was provided."}.constData()); // in case the TestedClass has setProperty()/property() methods. QObject &testedObj = static_cast(instance); QVERIFY2(metaProperty.isBindable() && metaProperty.isWritable(), - "Preconditions not met for " + QByteArray(propertyName)); + QByteArray{QByteArray("Preconditions not met for ") + propertyName}.constData()); QTestPrivate::OptionalWrapper spy = std::nullopt; if (metaProperty.hasNotifySignal()) @@ -336,15 +336,16 @@ void testWriteOncePropertyBasics( QObject &testedObj = static_cast(instance); QVERIFY2(metaProperty.metaType() == QMetaType::fromType(), - QByteArray("Preconditions not met for ") + propertyName + "\n" + QByteArray{QByteArray("Preconditions not met for ") + propertyName + "\n" "The type of prior and changed value does not match the type of the property.\n" "Please ensure that the types match exactly (convertability is not enough).\n" "You can provide the template types to the " "function explicitly to force a certain type.\n" "Property is " + metaProperty.metaType().name() - + " but parameters are " + QMetaType::fromType().name() + ".\n"); + + " but parameters are " + QMetaType::fromType().name() + ".\n"}.constData()); - QVERIFY2(metaProperty.isBindable(), "Preconditions not met for " + QByteArray(propertyName)); + QVERIFY2(metaProperty.isBindable(), + QByteArray{"Preconditions not met for " + QByteArray(propertyName)}.constData()); QUntypedBindable bindable = metaProperty.bindable(&instance); @@ -470,15 +471,16 @@ void testReadOnlyPropertyBasics( QObject &testedObj = static_cast(instance); QVERIFY2(metaProperty.metaType() == QMetaType::fromType(), - QByteArray("Preconditions not met for ") + propertyName + "\n" + QByteArray{QByteArray("Preconditions not met for ") + propertyName + "\n" "The type of initial and changed value does not match the type of the property.\n" "Please ensure that the types match exactly (convertability is not enough).\n" "You can provide the template types to the " "function explicitly to force a certain type.\n" "Expected was a " + metaProperty.metaType().name() - + " but " + QMetaType::fromType().name() + " was provided."); + + " but " + QMetaType::fromType().name() + " was provided."}.constData()); - QVERIFY2(metaProperty.isBindable(), "Preconditions not met for " + QByteArray(propertyName)); + QVERIFY2(metaProperty.isBindable(), + QByteArray{"Preconditions not met for " + QByteArray(propertyName)}.constData()); QUntypedBindable bindable = metaProperty.bindable(&instance); diff --git a/local/recipes/qt/qtbase/source/src/testlib/qtestcase.cpp b/local/recipes/qt/qtbase/source/src/testlib/qtestcase.cpp index 661f6206f0..e9f2cb8c79 100644 --- a/local/recipes/qt/qtbase/source/src/testlib/qtestcase.cpp +++ b/local/recipes/qt/qtbase/source/src/testlib/qtestcase.cpp @@ -1988,7 +1988,9 @@ int QTest::qRun() int remainingRepetitions = repetitions; const bool repeatForever = repetitions < 0; - while (QTestLog::failCount() == 0 && (repeatForever || remainingRepetitions-- > 0)) { + const int badArgCount = QTestLog::failCount(); // Stop if anything else fails. + while (!(QTestLog::failCount() > badArgCount) + && (repeatForever || remainingRepetitions-- > 0)) { QTestTable::globalTestTable(); test.invokeTests(currentTestObject); QTestTable::clearGlobalTestTable(); diff --git a/local/recipes/qt/qtbase/source/src/testlib/qtestkeyboard.h b/local/recipes/qt/qtbase/source/src/testlib/qtestkeyboard.h index b051bd9124..6dc776aa49 100644 --- a/local/recipes/qt/qtbase/source/src/testlib/qtestkeyboard.h +++ b/local/recipes/qt/qtbase/source/src/testlib/qtestkeyboard.h @@ -37,7 +37,8 @@ namespace QTest enum KeyAction { Press, Release, Click, Shortcut }; static void simulateEvent(QWindow *window, bool press, int code, - Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1) + Qt::KeyboardModifiers modifier, const QString &text, + bool repeat, int delay = -1) { QEvent::Type type; type = press ? QEvent::KeyPress : QEvent::KeyRelease; @@ -46,7 +47,8 @@ namespace QTest } static void sendKeyEvent(KeyAction action, QWindow *window, Qt::Key code, - QString text, Qt::KeyboardModifiers modifier, int delay=-1) + const QString &text, Qt::KeyboardModifiers modifier, + int delay = -1) { QTEST_ASSERT(qApp); @@ -148,7 +150,8 @@ namespace QTest #ifdef QT_WIDGETS_LIB static void simulateEvent(QWidget *widget, bool press, int code, - Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1) + Qt::KeyboardModifiers modifier, const QString &text, + bool repeat, int delay = -1) { QTEST_ASSERT(widget); extern int Q_TESTLIB_EXPORT defaultKeyDelay(); @@ -168,7 +171,8 @@ namespace QTest } static void sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code, - QString text, Qt::KeyboardModifiers modifier, int delay=-1) + const QString &text, Qt::KeyboardModifiers modifier, + int delay = -1) { QTEST_ASSERT(qApp); diff --git a/local/recipes/qt/qtbase/source/src/testlib/qtestresult.cpp b/local/recipes/qt/qtbase/source/src/testlib/qtestresult.cpp index 08b0a7848f..c88aeacce7 100644 --- a/local/recipes/qt/qtbase/source/src/testlib/qtestresult.cpp +++ b/local/recipes/qt/qtbase/source/src/testlib/qtestresult.cpp @@ -369,7 +369,7 @@ static int approx_wide_len(const char *s) auto r = std::mbsrtowcs(nullptr, &s, INT_MAX, &state); if (r == size_t(-1)) // encoding error, fall back to strlen() r = strlen(s); // `s` was not advanced since `dst == nullptr` - return q26::saturate_cast(r); + return q26::saturating_cast(r); } // Overload to format failures for "const char *" - no need to strdup(). diff --git a/local/recipes/qt/qtbase/source/src/tools/androidtestrunner/main.cpp b/local/recipes/qt/qtbase/source/src/tools/androidtestrunner/main.cpp index 161d95db49..72974a1838 100644 --- a/local/recipes/qt/qtbase/source/src/tools/androidtestrunner/main.cpp +++ b/local/recipes/qt/qtbase/source/src/tools/androidtestrunner/main.cpp @@ -896,12 +896,20 @@ struct TestRunnerSystemSemaphore void release() { +#if !defined(Q_OS_WIN32) + // Block signals around CAS + release sequence so that no signal arrives + // after isAcquired is cleared but before the OS semaphore is actually + // released (which would leave it held after _exit() call). + sigset_t newMask, oldMask; + sigfillset(&newMask); + sigprocmask(SIG_BLOCK, &newMask, &oldMask); +#endif bool expected = true; - // NOTE: There's still could be tiny time gap between the compare_exchange_strong() call - // and release() call where the thread could be interrupted, if that's ever an issue, - // this code could be checked and improved further. if (isAcquired.compare_exchange_strong(expected, false)) isAcquired.store(!semaphore.release()); +#if !defined(Q_OS_WIN32) + sigprocmask(SIG_SETMASK, &oldMask, nullptr); +#endif } std::atomic isAcquired { false }; @@ -1004,6 +1012,8 @@ int main(int argc, char *argv[]) if (!execBundletoolCommand({ "install-apks"_L1, "--apks"_L1, apksFilePath })) return EXIT_ERROR; + + g_testInfo.isPackageInstalled.store(true); } const QStringList dangerousPermisisons = queryDangerousPermissions(); @@ -1049,7 +1059,7 @@ int main(int argc, char *argv[]) int exitCode = testExitCode(); - if (g_options.showLogcatOutput) + if (g_options.showLogcatOutput || !isTestExitCodeNormal(exitCode)) analyseLogcat(formattedStartTime, &exitCode); const bool pullRes = pullResults(); diff --git a/local/recipes/qt/qtbase/source/src/tools/uic/python/pythonwriteimports.cpp b/local/recipes/qt/qtbase/source/src/tools/uic/python/pythonwriteimports.cpp index 3c6f5710ce..13679a9c90 100644 --- a/local/recipes/qt/qtbase/source/src/tools/uic/python/pythonwriteimports.cpp +++ b/local/recipes/qt/qtbase/source/src/tools/uic/python/pythonwriteimports.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "pythonwriteimports.h" +#include "language.h" #include #include @@ -78,7 +79,10 @@ static void formatImportClasses(QTextStream &str, QStringList classList) for (qsizetype i = 0; i < size; ++i) { if (i > 0) str << (i % 4 == 0 ? ",\n " : ", "); - str << classList.at(i); + QString name = language::fixClassName(classList.at(i)); + if (const auto dotPos = name.indexOf(u'.'); dotPos != -1) + name.truncate(dotPos); // Import outer class only in case of nested + str << name; } if (size > 1) str << ')'; @@ -215,9 +219,6 @@ bool WriteImports::addQtClass(const QString &className) void WriteImports::addPythonCustomWidget(const QString &className, const DomCustomWidget *node) { - if (className.contains("::"_L1)) - return; // Exclude namespaced names (just to make tests pass). - if (addQtClass(className)) // Qt custom widgets like QQuickWidget, QAxWidget, etc return; diff --git a/local/recipes/qt/qtbase/source/src/tools/uic/qclass_lib_map.h b/local/recipes/qt/qtbase/source/src/tools/uic/qclass_lib_map.h index e9e4cfde12..755c58a5a4 100644 --- a/local/recipes/qt/qtbase/source/src/tools/uic/qclass_lib_map.h +++ b/local/recipes/qt/qtbase/source/src/tools/uic/qclass_lib_map.h @@ -47,7 +47,6 @@ QT_CLASS_LIB(QForeachContainer, QtCore, qglobal.h) QT_CLASS_LIB(QLibraryInfo, QtCore, qlibraryinfo.h) QT_CLASS_LIB(Qt, QtCore, qnamespace.h) QT_CLASS_LIB(QInternal, QtCore, qnamespace.h) -QT_CLASS_LIB(QCOORD, QtCore, qnamespace.h) QT_CLASS_LIB(QtConfig, QtCore, qconfig.h) QT_CLASS_LIB(QBuffer, QtCore, qbuffer.h) QT_CLASS_LIB(QDataStream, QtCore, qdatastream.h) @@ -59,7 +58,6 @@ QT_CLASS_LIB(QDirIterator, QtCore, qdiriterator.h) QT_CLASS_LIB(QFile, QtCore, qfile.h) QT_CLASS_LIB(QFileInfo, QtCore, qfileinfo.h) QT_CLASS_LIB(QFileInfoList, QtCore, qfileinfo.h) -QT_CLASS_LIB(QFileInfoListIterator, QtCore, qfileinfo.h) QT_CLASS_LIB(QFileSystemWatcher, QtCore, qfilesystemwatcher.h) QT_CLASS_LIB(QIODevice, QtCore, qiodevice.h) QT_CLASS_LIB(QProcessEnvironment, QtCore, qprocess.h) @@ -70,7 +68,6 @@ QT_CLASS_LIB(QTemporaryFile, QtCore, qtemporaryfile.h) QT_CLASS_LIB(QTextStream, QtCore, qtextstream.h) QT_CLASS_LIB(QTextStreamFunction, QtCore, qtextstream.h) QT_CLASS_LIB(QTextStreamManipulator, QtCore, qtextstream.h) -QT_CLASS_LIB(QTS, QtCore, qtextstream.h) QT_CLASS_LIB(QUrl, QtCore, qurl.h) QT_CLASS_LIB(QAbstractEventDispatcher, QtCore, qabstracteventdispatcher.h) QT_CLASS_LIB(QModelIndex, QtCore, qabstractitemmodel.h) @@ -97,7 +94,6 @@ QT_CLASS_LIB(QMimeData, QtCore, qmimedata.h) QT_CLASS_LIB(QObjectList, QtCore, qobject.h) QT_CLASS_LIB(QObjectData, QtCore, qobject.h) QT_CLASS_LIB(QObject, QtCore, qobject.h) -QT_CLASS_LIB(QObjectUserData, QtCore, qobject.h) QT_CLASS_LIB(QObjectCleanupHandler, QtCore, qobjectcleanuphandler.h) QT_CLASS_LIB(QGenericArgument, QtCore, qobjectdefs.h) QT_CLASS_LIB(QGenericReturnArgument, QtCore, qobjectdefs.h) @@ -115,7 +111,6 @@ QT_CLASS_LIB(QVariant, QtCore, qvariant.h) QT_CLASS_LIB(QVariantList, QtCore, qvariant.h) QT_CLASS_LIB(QVariantMap, QtCore, qvariant.h) QT_CLASS_LIB(QVariantHash, QtCore, qvariant.h) -QT_CLASS_LIB(QVariantComparisonHelper, QtCore, qvariant.h) QT_CLASS_LIB(QFactoryInterface, QtCore, qfactoryinterface.h) QT_CLASS_LIB(QLibrary, QtCore, qlibrary.h) QT_CLASS_LIB(QtPlugin, QtCore, qplugin.h) @@ -148,7 +143,6 @@ QT_CLASS_LIB(QtAlgorithms, QtCore, qalgorithms.h) QT_CLASS_LIB(QBitArray, QtCore, qbitarray.h) QT_CLASS_LIB(QBitRef, QtCore, qbitarray.h) QT_CLASS_LIB(QByteArray, QtCore, qbytearray.h) -QT_CLASS_LIB(QByteRef, QtCore, qbytearray.h) QT_CLASS_LIB(QByteArrayMatcher, QtCore, qbytearraymatcher.h) QT_CLASS_LIB(QCache, QtCore, qcache.h) QT_CLASS_LIB(QLatin1Char, QtCore, qchar.h) @@ -184,8 +178,6 @@ QT_CLASS_LIB(QMutableListIterator, QtCore, qlist.h) QT_CLASS_LIB(QSystemLocale, QtCore, qlocale.h) QT_CLASS_LIB(QLocale, QtCore, qlocale.h) QT_CLASS_LIB(QMapData, QtCore, qmap.h) -QT_CLASS_LIB(QMapNode, QtCore, qmap.h) -QT_CLASS_LIB(QMapPayloadNode, QtCore, qmap.h) QT_CLASS_LIB(QMap, QtCore, qmap.h) QT_CLASS_LIB(QMultiMap, QtCore, qmap.h) QT_CLASS_LIB(QMapIterator, QtCore, qmap.h) @@ -216,12 +208,9 @@ QT_CLASS_LIB(QWeakPointer, QtCore, qsharedpointer.h) QT_CLASS_LIB(QSize, QtCore, qsize.h) QT_CLASS_LIB(QSizeF, QtCore, qsize.h) QT_CLASS_LIB(QStack, QtCore, qstack.h) -QT_CLASS_LIB(QStdWString, QtCore, qstring.h) QT_CLASS_LIB(QString, QtCore, qstring.h) QT_CLASS_LIB(QLatin1String, QtCore, qstring.h) QT_CLASS_LIB(QLatin1StringView, QtCore, qstring.h) -QT_CLASS_LIB(QCharRef, QtCore, qstring.h) -QT_CLASS_LIB(QLatin1Literal, QtCore, qstring.h) QT_CLASS_LIB(QAbstractConcatenable, QtCore, qstringbuilder.h) QT_CLASS_LIB(QConcatenable, QtCore, qstringbuilder.h) QT_CLASS_LIB(QStringBuilder, QtCore, qstringbuilder.h) @@ -267,17 +256,6 @@ QT_CLASS_LIB(QDomNotation, QtXml, qdom.h) QT_CLASS_LIB(QDomEntity, QtXml, qdom.h) QT_CLASS_LIB(QDomEntityReference, QtXml, qdom.h) QT_CLASS_LIB(QDomProcessingInstruction, QtXml, qdom.h) -QT_CLASS_LIB(QXmlStreamAttribute, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamAttributes, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamEntityDeclaration, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamEntityDeclarations, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamEntityResolver, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamNamespaceDeclaration, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamNamespaceDeclarations, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamNotationDeclaration, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamNotationDeclarations, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamReader, QtXml, qxmlstream.h) -QT_CLASS_LIB(QXmlStreamWriter, QtXml, qxmlstream.h) QT_CLASS_LIB(QNetworkCacheMetaData, QtNetwork, qabstractnetworkcache.h) QT_CLASS_LIB(QAbstractNetworkCache, QtNetwork, qabstractnetworkcache.h) QT_CLASS_LIB(QNetworkAccessManager, QtNetwork, qnetworkaccessmanager.h) diff --git a/local/recipes/qt/qtbase/source/src/tools/uic/shared/language.cpp b/local/recipes/qt/qtbase/source/src/tools/uic/shared/language.cpp index 6ff5987522..9182ce2a00 100644 --- a/local/recipes/qt/qtbase/source/src/tools/uic/shared/language.cpp +++ b/local/recipes/qt/qtbase/source/src/tools/uic/shared/language.cpp @@ -104,8 +104,14 @@ QLatin1StringView lookupEnum(const EnumLookup(&array)[N], int value, int default QString fixClassName(QString className) { - if (language() == Language::Python) - className.replace(cppQualifier, "_"_L1); + switch (language()) { + case Language::Cpp: + className.replace(u'.', cppQualifier); // Nested Python class name + break; + case Language::Python: + className.replace(cppQualifier, "."_L1); + break; + } return className; } diff --git a/local/recipes/qt/qtbase/source/src/tools/windeployqt/main.cpp b/local/recipes/qt/qtbase/source/src/tools/windeployqt/main.cpp index 6cb935ef47..839a0b4cfb 100644 --- a/local/recipes/qt/qtbase/source/src/tools/windeployqt/main.cpp +++ b/local/recipes/qt/qtbase/source/src/tools/windeployqt/main.cpp @@ -1007,20 +1007,27 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir, const boo { const QString subDirName = subDir.dirName(); // Filter out disabled plugins - if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) { - std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n'; + if (pluginSelections.disabledPluginTypes.contains(subDirName)) { + if (optVerboseLevel) { + std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " + << subDirName << '\n'; + } return {}; } - if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker") + if (subDirName == u"generic" && plugin.contains(u"qinsighttracker") && !deployInsightTrackerPlugin) { - std::wcout << "Skipping plugin " << plugin - << ". Use -deploy-insighttracker if you want to use it.\n"; + if (optVerboseLevel) { + std::wcout << "Skipping plugin " << plugin + << ". Use -deploy-insighttracker if you want to use it.\n"; + } return {}; } - if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend") + if (subDirName == u"tls" && plugin.contains(u"qopensslbackend") && !deployOpenSslPlugin) { - std::wcout << "Skipping plugin " << plugin - << ". Use -force-openssl or specify -openssl-root if you want to use it.\n"; + if (optVerboseLevel) { + std::wcout << "Skipping plugin " << plugin + << ". Use -force-openssl or specify -openssl-root if you want to use it.\n"; + } return {}; } @@ -1032,8 +1039,9 @@ static QString deployPlugin(const QString &plugin, const QDir &subDir, const boo : dotIndex; const QString pluginName = plugin.first(stripIndex); - if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) { - std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n'; + if (pluginSelections.excludedPlugins.contains(pluginName)) { + if (optVerboseLevel) + std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n'; return {}; } @@ -1359,6 +1367,27 @@ static QString vcRedistDir() return QString(); } +static bool isSystemLibrary(const QString &libraryPath) +{ + static const QString systemRootEnv = qEnvironmentVariable("SystemRoot"); + static bool systemRootEmptyEmitted = false; + if (systemRootEnv.isEmpty()) { + if (!systemRootEmptyEmitted) { + std::wcerr << "Warning: Cannot detect system root.\n"; + systemRootEmptyEmitted = true; + } + return false; + } + static QString systemRoot; + if (systemRoot.isEmpty()) { + systemRoot = QDir(QDir::fromNativeSeparators(systemRootEnv)).canonicalPath(); + if (!systemRoot.endsWith(u'/')) + systemRoot += u'/'; + } + + return libraryPath.startsWith(systemRoot, Qt::CaseInsensitive); +} + static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters) { //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found. @@ -1764,10 +1793,12 @@ static DeployResult deploy(const Options &options, const QMap if (options.systemDxc) { const QStringList dxcLibs = findDxc(options.platform, qtBinDir, peHeaderInfo.wordSize); - if (!dxcLibs.isEmpty()) + if (!dxcLibs.isEmpty()) { deployedQtLibraries.append(dxcLibs); - else - std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n"; + } else { + std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll." + << " This is not a problem unless Direct3D 12 and certain features are used by the application.\n"; + } } } // Windows @@ -1787,6 +1818,10 @@ static DeployResult deploy(const Options &options, const QMap peHeaderInfo.machineArch)); } for (const QString &qtLib : std::as_const(libraries)) { + if (isSystemLibrary(qtLib)) { + std::wcout << "Skipping system library " << qtLib << "\n"; + continue; + } if (!updateLibrary(qtLib, targetPath, options, errorMessage)) return result; } diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qcolordialog.cpp b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qcolordialog.cpp index bb4ba136b7..68783ade17 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qcolordialog.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qcolordialog.cpp @@ -370,17 +370,6 @@ void QWellArray::keyPressEvent(QKeyEvent* e) if (curRow < numRows()-1) setCurrent(curRow + 1, curCol); break; -#if 0 - // bad idea that shouldn't have been implemented; very counterintuitive - case Qt::Key_Return: - case Qt::Key_Enter: - /* - ignore the key, so that the dialog get it, but still select - the current row/col - */ - e->ignore(); - // fallthrough intended -#endif case Qt::Key_Space: setSelected(curRow, curCol); break; diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog.cpp b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog.cpp index b324c5b852..b949976ace 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // Qt-Security score:significant reason:default +#include "kernel/qwidget_p.h" #include +#include #if QT_CONFIG(colordialog) #include "qcolordialog.h" #endif @@ -150,6 +152,16 @@ void QDialogPrivate::close(int resultCode) resetModalitySetByOpen(); } +void QDialogPrivate::recreate() +{ + // Calling destroy while having the eventLoop pointer in place would cause the + // event loop to exit - however, with recreate, we do not actually want this behavior + // but want to keep the QDialog alive, just with a different RHI configuration + QPointer existingEventLoop = std::exchange(eventLoop, nullptr); + QWidgetPrivate::recreate(); + eventLoop = existingEventLoop; +} + QWindow *QDialogPrivate::transientParentWindow() const { Q_Q(const QDialog); diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog_p.h b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog_p.h index 41aac8a6d8..f98fd69338 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qdialog_p.h @@ -90,6 +90,8 @@ public: void close(int resultCode); + void recreate() override; + protected: virtual int dialogCode() const { return rescode; } diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qmessagebox.cpp b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qmessagebox.cpp index 541721a79b..048cd1f39d 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qmessagebox.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qmessagebox.cpp @@ -250,6 +250,7 @@ public: QByteArray memberToDisconnectOnClose; QByteArray signalToDisconnectOnClose; QSharedPointer options; + bool optionsExplicitlySet = false; private: void initHelper(QPlatformDialogHelper *) override; void helperPrepareShow(QPlatformDialogHelper *) override; @@ -1265,6 +1266,9 @@ QCheckBox* QMessageBox::checkBox() const */ void QMessageBox::setOption(QMessageBox::Option option, bool on) { + Q_D(QMessageBox); + d->optionsExplicitlySet = true; + const QMessageBox::Options previousOptions = options(); if (!(previousOptions & option) != !on) setOptions(previousOptions ^ option); @@ -1287,10 +1291,10 @@ bool QMessageBox::testOption(QMessageBox::Option option) const void QMessageBox::setOptions(QMessageBox::Options options) { Q_D(QMessageBox); + d->optionsExplicitlySet = true; if (QMessageBox::options() == options) return; - d->options->setOptions(QMessageDialogOptions::Option(int(options))); } @@ -1492,7 +1496,8 @@ void QMessageBox::setTextInteractionFlags(Qt::TextInteractionFlags flags) */ bool QMessageBox::event(QEvent *e) { - bool result =QDialog::event(e); + Q_D(QMessageBox); + bool result = QDialog::event(e); switch (e->type()) { case QEvent::LayoutRequest: d_func()->updateSize(); @@ -1500,6 +1505,10 @@ bool QMessageBox::event(QEvent *e) case QEvent::LanguageChange: d_func()->retranslateStrings(); break; + case QEvent::Polish: + if (!d->optionsExplicitlySet && metaObject() != &QMessageBox::staticMetaObject) + setOption(QMessageBox::Option::DontUseNativeDialog); + break; default: break; } @@ -2820,9 +2829,6 @@ bool QMessageBoxPrivate::canBeNativeDialog() const return false; } - if (strcmp(QMessageBox::staticMetaObject.className(), q->metaObject()->className()) != 0) - return false; - #if QT_CONFIG(menu) for (auto *customButton : buttonBox->buttons()) { if (QPushButton *pushButton = qobject_cast(customButton)) { diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qsidebar.cpp b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qsidebar.cpp index 1ac2271fa8..d567f7bc97 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qsidebar.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qsidebar.cpp @@ -46,7 +46,7 @@ QUrlModel::QUrlModel(QObject *parent) : QStandardItemModel(parent), showFullPath QUrlModel::~QUrlModel() { - for (const auto &conn : std::as_const(modelConnections)) + for (auto &conn : modelConnections) disconnect(conn); } @@ -288,7 +288,7 @@ void QUrlModel::setFileSystemModel(QFileSystemModel *model) if (model == fileSystemModel) return; if (fileSystemModel != nullptr) { - for (const auto &conn : std::as_const(modelConnections)) + for (auto &conn : modelConnections) disconnect(conn); } fileSystemModel = model; diff --git a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qwizard.cpp b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qwizard.cpp index 38ef6cfb89..af39865e74 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/dialogs/qwizard.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/dialogs/qwizard.cpp @@ -397,14 +397,25 @@ void QWizardHeader::paintEvent(QPaintEvent * /* event */) painter.drawPixmap(0, 0, bannerPixmap); } - int x = width() - 2; - int y = height() - 2; + // With fractional scaling the 1px difference in y-coordinate can map to + // the same pixel, so make sure that we take DPR into account when drawing + // the lines. + const qreal dpr = devicePixelRatio(); + const int devHeight = qRound(height() * dpr); + const int devWidth = qRound(width() * dpr); + + const qreal x = (devWidth - 2) / dpr; + const qreal y = (devHeight - 2) / dpr; + + const qreal x1 = (devWidth - 1) / dpr; + const qreal y1 = (devHeight - 1) / dpr; + const QPalette &pal = palette(); painter.setPen(pal.mid().color()); - painter.drawLine(0, y, x, y); + painter.drawLine(QLineF(0, y, x, y)); painter.setPen(pal.base().color()); - painter.drawPoint(x + 1, y); - painter.drawLine(0, y + 1, x + 1, y + 1); + painter.drawPoint(QPointF(x1, y)); + painter.drawLine(QLineF(0, y1, x1, y1)); } // We save one vtable by basing QWizardRuler on QWizardHeader diff --git a/local/recipes/qt/qtbase/source/src/widgets/doc/snippets/code/src_gui_widgets_qpushbutton.cpp b/local/recipes/qt/qtbase/source/src/widgets/doc/snippets/code/src_gui_widgets_qpushbutton.cpp index 35827bcba2..c53218b105 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/doc/snippets/code/src_gui_widgets_qpushbutton.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/doc/snippets/code/src_gui_widgets_qpushbutton.cpp @@ -4,3 +4,7 @@ //! [0] QPushButton *button = new QPushButton("&Download", this); //! [0] + +//! [clicked] +connect(dispenseButton, &QPushButton::clicked, this, &IceCreamMaker::dispense); +//! [clicked] diff --git a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.cpp index c6d070e14a..66f1e6cf91 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.cpp @@ -639,21 +639,4 @@ QSizeF QGraphicsGridLayout::sizeHint(Qt::SizeHint which, const QSizeF &constrain return d->engine.sizeHint(which , constraint - extraMargins, d->styleInfo()) + extraMargins; } - -#if 0 -// ### kill? (implement and kill?) -QRect QGraphicsGridLayout::cellRect(int row, int column, int rowSpan, int columnSpan) const -{ - Q_D(const QGraphicsGridLayout); - return QRect(); -// return d->engine.cellRect(parentLayoutable(), contentsGeometry(), row, column, rowSpan, columnSpan); -} - -QSizePolicy::ControlTypes QGraphicsGridLayout::controlTypes(LayoutSide side) const -{ - Q_D(const QGraphicsGridLayout); - return d->engine.controlTypes(side); -} -#endif - QT_END_NAMESPACE diff --git a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.h b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.h index f89687dc62..19b3f8bc34 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.h +++ b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicsgridlayout.h @@ -82,10 +82,6 @@ public: void setGeometry(const QRectF &rect) override; QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override; - // #### - //QRect cellRect(int row, int column, int rowSpan = 1, int columnSpan = 1) const; - //QSizePolicy::ControlTypes controlTypes(LayoutSide side) const; - private: Q_DISABLE_COPY(QGraphicsGridLayout) Q_DECLARE_PRIVATE(QGraphicsGridLayout) diff --git a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.cpp index 0bb479ba22..437da48f73 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.cpp @@ -427,13 +427,6 @@ Qt::Alignment QGraphicsLinearLayout::alignment(QGraphicsLayoutItem *item) const return d->engine.alignment(item); } -#if 0 // ### -QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) const -{ - return d->engine.controlTypes(side); -} -#endif - /*! \reimp */ diff --git a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.h b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.h index 8a2b15b18e..6f8d765e6b 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.h +++ b/local/recipes/qt/qtbase/source/src/widgets/graphicsview/qgraphicslinearlayout.h @@ -53,10 +53,6 @@ public: void invalidate() override; QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override; -#if 0 // ### - Q5SizePolicy::ControlTypes controlTypes(LayoutSide side) const; -#endif - void dump(int indent = 0) const; protected: diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview.cpp index e3aeafe44e..241faea293 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview.cpp @@ -287,9 +287,9 @@ void QAbstractItemViewPrivate::disconnectDelegate(QAbstractItemDelegate *delegat void QAbstractItemViewPrivate::disconnectAll() { Q_Q(QAbstractItemView); - for (const QMetaObject::Connection &connection : modelConnections) + for (QMetaObject::Connection &connection : modelConnections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : scrollbarConnections) + for (QMetaObject::Connection &connection : scrollbarConnections) QObject::disconnect(connection); disconnectDelegate(itemDelegate); for (QAbstractItemDelegate *delegate : std::as_const(rowDelegates)) @@ -756,7 +756,7 @@ void QAbstractItemView::setModel(QAbstractItemModel *model) if (model == d->model) return; if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { - for (const QMetaObject::Connection &connection : d->modelConnections) + for (QMetaObject::Connection &connection : d->modelConnections) disconnect(connection); } d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel()); @@ -941,7 +941,8 @@ QVariant QAbstractItemView::inputMethodQuery(Qt::InputMethodQuery query) const result = QRect(currentEditor->mapTo(this, editorRect.topLeft()), editorRect.size()); } } else if (query == Qt::ImCursorRectangle) { - result = visualRect(current); + const QRect visRect = visualRect(current); + result = QRect(d->viewport->mapTo(this, visRect.topLeft()), visRect.size()); } } if (!result.isValid()) @@ -1850,13 +1851,12 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid(); QPoint offset = d->offset(); - d->draggedPosition = pos; - d->draggedPositionOffset = offset; + d->draggedPosition = pos + offset; #if QT_CONFIG(draganddrop) // update the pressed position when drag was enable if (d->dragEnabled) - d->pressedPosition = d->draggedPosition + d->draggedPositionOffset; + d->pressedPosition = d->draggedPosition; #endif if (!(command & QItemSelectionModel::Current)) { @@ -1913,8 +1913,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) Q_D(QAbstractItemView); QPoint bottomRight = event->position().toPoint(); - d->draggedPosition = bottomRight; - d->draggedPositionOffset = d->offset(); + d->draggedPosition = bottomRight + d->offset(); if (state() == ExpandingState || state() == CollapsingState) return; @@ -2089,8 +2088,7 @@ void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event) void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event) { Q_D(QAbstractItemView); - d->draggedPosition = event->position().toPoint(); - d->draggedPositionOffset = d->offset(); + d->draggedPosition = event->position().toPoint() + d->offset(); if (dragDropMode() == InternalMove && (event->source() != this || !(event->possibleActions() & Qt::MoveAction))) return; @@ -4161,8 +4159,7 @@ void QAbstractItemView::doAutoScroll() const int verticalValue = verticalScroll->value(); const int horizontalValue = horizontalScroll->value(); - const QPoint pos = d->draggedPosition; - + const QPoint pos = d->draggedPosition - d->offset(); const QRect area = QWidgetPrivate::get(d->viewport)->clipRect(); // do the scrolling if we are in the scroll margins @@ -4202,8 +4199,7 @@ void QAbstractItemView::doAutoScroll() // update our dragged position manually after the scroll. "pos" is the old // draggedPosition - d->offset(), and d->offset() is now updated after scrolling, so // pos + d->offset() gives us the new position. - d->draggedPosition = pos; - d->draggedPositionOffset = d->offset(); + d->draggedPosition = pos + d->offset(); break; } default: diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview_p.h b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview_p.h index f9e899d7fc..a39752b0a0 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qabstractitemview_p.h @@ -364,7 +364,6 @@ public: Qt::KeyboardModifiers pressedModifiers; QPoint pressedPosition; QPoint draggedPosition; - QPoint draggedPositionOffset; bool pressedAlreadySelected; bool releaseFromDoubleClick; diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview.cpp index fb02a290cf..61eb6b0a57 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview.cpp @@ -79,26 +79,22 @@ void QColumnViewPrivate::initialize() q->setItemDelegate(new QColumnViewDelegate(q)); } -void QColumnViewPrivate::clearConnections() -{ -#if QT_CONFIG(animation) - QObject::disconnect(animationConnection); -#endif - for (const QMetaObject::Connection &connection : gripConnections) - QObject::disconnect(connection); - const auto copy = viewConnections; // disconnectView modifies this container - for (auto it = copy.keyBegin(); it != copy.keyEnd(); ++it) - disconnectView(*it); -} - - /*! Destroys the column view. */ QColumnView::~QColumnView() { Q_D(QColumnView); - d->clearConnections(); + // clear all connections: +#if QT_CONFIG(animation) + disconnect(d->animationConnection); +#endif + for (QMetaObject::Connection &conn : d->gripConnections) + disconnect(conn); + for (auto &&[_, conns] : d->viewConnections) { + for (QMetaObject::Connection &conn : conns) + disconnect(conn); + } } /*! @@ -648,7 +644,7 @@ void QColumnViewPrivate::disconnectView(QAbstractItemView *view) const auto it = viewConnections.find(view); if (it == viewConnections.end()) return; - for (const QMetaObject::Connection &connection : it.value()) + for (QMetaObject::Connection &connection : it.value()) QObject::disconnect(connection); viewConnections.erase(it); } @@ -705,7 +701,7 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo QObject::connect(view, &QAbstractItemView::doubleClicked, q, &QColumnView::doubleClicked), QObject::connect(view, &QAbstractItemView::entered, q, &QColumnView::entered), QObject::connect(view, &QAbstractItemView::pressed, q, &QColumnView::pressed), - clickedConnection + std::move(clickedConnection), }; view->setFocusPolicy(Qt::NoFocus); diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview_p.h b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview_p.h index 8c04cb9242..2804497530 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qcolumnview_p.h @@ -32,6 +32,8 @@ #include #include +#include + #include QT_REQUIRE_CONFIG(columnview); @@ -120,7 +122,6 @@ public: QColumnViewPrivate(); ~QColumnViewPrivate(); void initialize(); - void clearConnections(); QAbstractItemView *createColumn(const QModelIndex &index, bool show); @@ -148,8 +149,8 @@ public: QMetaObject::Connection animationConnection; #endif std::vector gripConnections; - using ViewConnections = std::vector; - QHash viewConnections; + using ViewConnections = std::array; + QVarLengthFlatMap viewConnections; QWidget *previewWidget; QAbstractItemView *previewColumn; diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qdatawidgetmapper.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qdatawidgetmapper.cpp index 8cb74a24c0..ec8cec01d0 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qdatawidgetmapper.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qdatawidgetmapper.cpp @@ -78,12 +78,12 @@ public: void disconnectModel() { - for (const QMetaObject::Connection &connection : modelConnections) + for (QMetaObject::Connection &connection : modelConnections) QObject::disconnect(connection); } void disconnectDelegate() { - for (const QMetaObject::Connection &connection : delegateConnections) + for (QMetaObject::Connection &connection : delegateConnections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview.cpp index 0911bb4e7c..de03b49ce5 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview.cpp @@ -426,7 +426,7 @@ void QHeaderView::setOffset(int newOffset) if (d->headerOffset == newOffset) return; // don't overflow; this function is checked with both INT_MIN and INT_MAX... - const int ndelta = q26::saturate_cast(d->headerOffset - qint64{newOffset}); + const int ndelta = q26::saturating_cast(d->headerOffset - qint64{newOffset}); d->headerOffset = newOffset; if (d->orientation == Qt::Horizontal) { if (isRightToLeft()) { @@ -2711,8 +2711,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) } case QHeaderViewPrivate::MoveSection: { if (d->shouldAutoScroll(e->position().toPoint())) { - d->draggedPosition = e->pos(); - d->draggedPositionOffset = d->offset(); + d->draggedPosition = e->pos() + d->offset(); d->startAutoScroll(); } if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance() diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview_p.h b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview_p.h index 1cd5af2c95..382eb0dc5e 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qheaderview_p.h @@ -233,7 +233,7 @@ public: inline void disconnectModel() { - for (const QMetaObject::Connection &connection : modelConnections) + for (QMetaObject::Connection &connection : modelConnections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qlistwidget.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qlistwidget.cpp index 54279efe2f..edac247de0 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qlistwidget.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qlistwidget.cpp @@ -1103,9 +1103,9 @@ void QListWidgetPrivate::setup() void QListWidgetPrivate::clearConnections() { - for (const QMetaObject::Connection &connection : connections) + for (QMetaObject::Connection &connection : connections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : selectionModelConnections) + for (QMetaObject::Connection &connection : selectionModelConnections) QObject::disconnect(connection); } @@ -1386,7 +1386,7 @@ void QListWidget::setSelectionModel(QItemSelectionModel *selectionModel) { Q_D(QListWidget); - for (const QMetaObject::Connection &connection : d->selectionModelConnections) + for (QMetaObject::Connection &connection : d->selectionModelConnections) disconnect(connection); QListView::setSelectionModel(selectionModel); diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview.cpp index 94a937b74b..6e4dc5607a 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview.cpp @@ -606,13 +606,13 @@ void QTableViewPrivate::init() void QTableViewPrivate::clearConnections() { - for (const QMetaObject::Connection &connection : modelConnections) + for (QMetaObject::Connection &connection : modelConnections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : verHeaderConnections) + for (QMetaObject::Connection &connection : verHeaderConnections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : horHeaderConnections) + for (QMetaObject::Connection &connection : horHeaderConnections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : dynHorHeaderConnections) + for (QMetaObject::Connection &connection : dynHorHeaderConnections) QObject::disconnect(connection); QObject::disconnect(selectionmodelConnection); #if QT_CONFIG(abstractbutton) @@ -1289,7 +1289,7 @@ void QTableView::setModel(QAbstractItemModel *model) return; //let's disconnect from the old model if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { - for (const QMetaObject::Connection &connection : d->modelConnections) + for (QMetaObject::Connection &connection : d->modelConnections) disconnect(connection); } if (d->selectionModel) { // support row editing @@ -1395,7 +1395,7 @@ void QTableView::setHorizontalHeader(QHeaderView *header) if (!header || header == d->horizontalHeader) return; - for (const QMetaObject::Connection &connection : d->horHeaderConnections) + for (QMetaObject::Connection &connection : d->horHeaderConnections) disconnect(connection); if (d->horizontalHeader && d->horizontalHeader->parent() == this) delete d->horizontalHeader; @@ -1435,7 +1435,7 @@ void QTableView::setVerticalHeader(QHeaderView *header) if (!header || header == d->verticalHeader) return; - for (const QMetaObject::Connection &connection : d->verHeaderConnections) + for (QMetaObject::Connection &connection : d->verHeaderConnections) disconnect(connection); if (d->verticalHeader && d->verticalHeader->parent() == this) delete d->verticalHeader; @@ -2763,9 +2763,8 @@ void QTableView::setSortingEnabled(bool enable) { Q_D(QTableView); horizontalHeader()->setSortIndicatorShown(enable); - for (const QMetaObject::Connection &connection : d->dynHorHeaderConnections) + for (QMetaObject::Connection &connection : d->dynHorHeaderConnections) disconnect(connection); - d->dynHorHeaderConnections.clear(); if (enable) { //sortByColumn has to be called before we connect or set the sortingEnabled flag // because otherwise it will not call sort on the model. diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview_p.h b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview_p.h index bdd8d7d136..aa8dbf09a2 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtableview_p.h @@ -28,7 +28,6 @@ #include #include -#include QT_REQUIRE_CONFIG(tableview); @@ -177,7 +176,7 @@ public: std::array modelConnections; std::array verHeaderConnections; std::array horHeaderConnections; - std::vector dynHorHeaderConnections; + std::array dynHorHeaderConnections; bool sortingEnabled; bool geometryRecursionBlock; diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtablewidget.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtablewidget.cpp index 85b399746b..2c2e0cf41e 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtablewidget.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtablewidget.cpp @@ -1644,7 +1644,7 @@ void QTableWidgetPrivate::setup() void QTableWidgetPrivate::clearConnections() { - for (const QMetaObject::Connection &connection : connections) + for (QMetaObject::Connection &connection : connections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview.cpp index 1223c47f4c..b82701cc90 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview.cpp @@ -187,7 +187,7 @@ void QTreeView::setModel(QAbstractItemModel *model) if (model == d->model) return; if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { - for (const QMetaObject::Connection &connection : d->modelConnections) + for (QMetaObject::Connection &connection : d->modelConnections) QObject::disconnect(connection); } @@ -3141,9 +3141,9 @@ void QTreeViewPrivate::initialize() void QTreeViewPrivate::clearConnections() { - for (const QMetaObject::Connection &connection : modelConnections) + for (QMetaObject::Connection &connection : modelConnections) QObject::disconnect(connection); - for (const QMetaObject::Connection &connection : headerConnections) + for (QMetaObject::Connection &connection : headerConnections) QObject::disconnect(connection); QObject::disconnect(selectionmodelConnection); QObject::disconnect(sortHeaderConnection); @@ -3205,21 +3205,6 @@ void QTreeViewPrivate::removeViewItems(int pos, int count) items[i].parentItem -= count; } -#if 0 -bool QTreeViewPrivate::checkViewItems() const -{ - for (int i = 0; i < viewItems.count(); ++i) { - const QTreeViewItem &vi = viewItems.at(i); - if (vi.parentItem == -1) { - Q_ASSERT(!vi.index.parent().isValid() || vi.index.parent() == root); - } else { - Q_ASSERT(vi.index.parent() == viewItems.at(vi.parentItem).index); - } - } - return true; -} -#endif - void QTreeViewPrivate::collapse(int item, bool emitSignal) { Q_Q(QTreeView); diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview_p.h b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview_p.h index 34db2fcdac..2df0915369 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreeview_p.h @@ -124,9 +124,6 @@ public: void insertViewItems(int pos, int count, const QTreeViewItem &viewItem); void removeViewItems(int pos, int count); -#if 0 - bool checkViewItems() const; -#endif int firstVisibleItem(int *offset = nullptr) const; int lastVisibleItem(int firstVisual = -1, int offset = -1) const; diff --git a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreewidget.cpp b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreewidget.cpp index f8ffaba3ec..37819c7246 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreewidget.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/itemviews/qtreewidget.cpp @@ -2292,7 +2292,7 @@ QDataStream &operator>>(QDataStream &in, QTreeWidgetItem &item) void QTreeWidgetPrivate::clearConnections() { - for (const QMetaObject::Connection &connection : connections) + for (QMetaObject::Connection &connection : connections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qgridlayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/kernel/qgridlayout.cpp index 77c6b558ae..f8bd6afab5 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qgridlayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qgridlayout.cpp @@ -314,23 +314,6 @@ QGridLayoutPrivate::QGridLayoutPrivate() verticalSpacing = -1; } -#if 0 -QGridLayoutPrivate::QGridLayoutPrivate(int nRows, int nCols) - : rowData(0), colData(0) -{ - init(); - if (nRows < 0) { - nRows = 1; - addVertical = false; - } - if (nCols < 0) { - nCols = 1; - addVertical = true; - } - setSize(nRows, nCols); -} -#endif - void QGridLayoutPrivate::deleteAll() { while (!things.isEmpty()) diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwhatsthis.cpp b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwhatsthis.cpp index bc91c76494..0409672164 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwhatsthis.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwhatsthis.cpp @@ -126,8 +126,8 @@ QWhatsThat *QWhatsThat::instance = nullptr; // shadowWidth not const, for XP drop-shadow-fu turns it to 0 static int shadowWidth = 6; // also used as '5' and '6' and even '8' below -static const int vMargin = 8; -static const int hMargin = 12; +static constexpr int vMargin = 8; +static constexpr int hMargin = 12; static inline bool dropShadow() { @@ -198,7 +198,7 @@ void QWhatsThat::mousePressEvent(QMouseEvent* e) pressed = true; if (e->button() == Qt::LeftButton && rect().contains(e->position().toPoint())) { if (doc) - anchor = doc->documentLayout()->anchorAt(e->position().toPoint() - QPoint(hMargin, vMargin)); + anchor = doc->documentLayout()->anchorAt(e->position() - QPointF(hMargin, vMargin)); return; } close(); @@ -209,7 +209,7 @@ void QWhatsThat::mouseReleaseEvent(QMouseEvent* e) if (!pressed) return; if (widget && e->button() == Qt::LeftButton && doc && rect().contains(e->position().toPoint())) { - QString a = doc->documentLayout()->anchorAt(e->position().toPoint() - QPoint(hMargin, vMargin)); + QString a = doc->documentLayout()->anchorAt(e->position() - QPointF(hMargin, vMargin)); QString href; if (anchor == a) href = a; @@ -230,7 +230,7 @@ void QWhatsThat::mouseMoveEvent(QMouseEvent* e) #else if (!doc) return; - QString a = doc->documentLayout()->anchorAt(e->position().toPoint() - QPoint(hMargin, vMargin)); + QString a = doc->documentLayout()->anchorAt(e->position() - QPointF(hMargin, vMargin)); if (!a.isEmpty()) setCursor(Qt::PointingHandCursor); else @@ -556,10 +556,9 @@ void QWhatsThisPrivate::say(QWidget * widget, const QString &text, int x, int y) // squeeze it in if that would result in part of what's this // being only partially visible - if (x + w + shadowWidth > sx+screenRect.width()) { - x = (widget ? qMin(screenRect.width(), pos.x() + widget->width()) - : screenRect.width()) - - w; + if (x + w + shadowWidth > screenRect.right()) { + x = widget ? qMin(screenRect.right(), pos.x() + widget->width()) : screenRect.right(); + x -=w; } if (x < sx) @@ -568,17 +567,16 @@ void QWhatsThisPrivate::say(QWidget * widget, const QString &text, int x, int y) if (widget && h > widget->height() + 16) { y = pos.y() + widget->height() + 2; // below, two pixels spacing // what's this is above or below, wherever there's most space - if (y + h + 10 > sy + screenRect.height()) + if (y + h + 10 > screenRect.bottom()) y = pos.y() + 2 - shadowWidth - h; // above, overlap } y = y + 2; // squeeze it in if that would result in part of what's this // being only partially visible - if (y + h + shadowWidth > sy + screenRect.height()) { - y = (widget ? qMin(screenRect.height(), pos.y() + widget->height()) - : screenRect.height()) - - h; + if (y + h + shadowWidth > screenRect.bottom()) { + y = widget ? qMin(screenRect.bottom(), pos.y() + widget->height()) : screenRect.bottom(); + y -= h; } if (y < sy) y = sy; diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget.cpp b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget.cpp index d42ddd44ec..684b1d6c4c 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget.cpp @@ -44,7 +44,6 @@ #include "private/qstyle_p.h" #include "qfileinfo.h" #include "qscopeguard.h" -#include #include #if QT_CONFIG(graphicseffect) @@ -943,8 +942,9 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) #if QT_DEPRECATED_SINCE(6, 11) QT_IGNORE_DEPRECATIONS( - Q_ASSERT_X(!f.testFlag(Qt::WindowType::Desktop), Q_FUNC_INFO, "Qt::WindowType::Desktop is not allowed."); - if (f.testFlag(Qt::WindowType::Desktop)) + const bool isDesktopWindow = (f & Qt::WindowType_Mask) == Qt::WindowType::Desktop; + Q_ASSERT_X(!isDesktopWindow, Q_FUNC_INFO, "Qt::WindowType::Desktop is not allowed."); + if (isDesktopWindow) f.setFlag(Qt::WindowType::Desktop, false); ) #endif @@ -10656,7 +10656,7 @@ void QWidgetPrivate::setWindowFlags(Qt::WindowFlags flags) Q_Q(QWidget); #if QT_DEPRECATED_SINCE(6, 11) QT_IGNORE_DEPRECATIONS( - if (flags.testFlag(Qt::WindowType::Desktop)) { + if ((flags & Qt::WindowType_Mask) == Qt::WindowType::Desktop) { qWarning() << "Qt::WindowType::Desktop has been deprecated in Qt 6. Ignoring."; flags.setFlag(Qt::WindowType::Desktop, false); } @@ -10970,8 +10970,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) const auto windowStateBeforeDestroy = newParentWithWindow->windowState(); const auto visibilityBeforeDestroy = newParentWithWindow->isVisible(); const auto positionBeforeDestroy = newParentWithWindow->pos(); - newParentWithWindow->destroy(); - newParentWithWindow->create(); + newParentWithWindow->d_func()->recreate(); Q_ASSERT(newParentWithWindow->windowHandle()); newParentWithWindow->windowHandle()->setWindowStates(windowStateBeforeDestroy); newParentWithWindow->move(positionBeforeDestroy); @@ -13872,7 +13871,7 @@ bool QWidgetPrivate::isInFocusChain() const bool QWidgetPrivate::isFocusChainConsistent() const { Q_Q(const QWidget); - const bool skip = !QLoggingCategory("qt.widgets.focus").isDebugEnabled(); + const bool skip = !lcWidgetFocus().isDebugEnabled(); if (skip) return true; diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget_p.h b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget_p.h index 969968b6f2..2d67b9a281 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidget_p.h @@ -441,6 +441,14 @@ public: // sub-classes that their internals are about to be released. virtual void aboutToDestroy() {} + // customization point for widget re-creation to deal with different RHI types + virtual void recreate() + { + Q_Q(QWidget); + q->destroy(); + q->create(); + } + inline QWidget *effectiveFocusWidget() { QWidget *w = q_func(); while (w->focusProxy()) diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidgetrepaintmanager.cpp b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidgetrepaintmanager.cpp index 30526e38b3..90df68d4f9 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidgetrepaintmanager.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwidgetrepaintmanager.cpp @@ -23,7 +23,6 @@ #include #endif #include -#include #include diff --git a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwindowcontainer.cpp b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwindowcontainer.cpp index 8472704c02..92e022bee9 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/kernel/qwindowcontainer.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/kernel/qwindowcontainer.cpp @@ -5,6 +5,7 @@ #include "qwindowcontainer_p.h" #include "qwidget_p.h" #include "qwidgetwindow_p.h" +#include #include #include #include @@ -31,6 +32,7 @@ public: QWindowContainerPrivate() : window(nullptr) , usesNativeWidgets(false) + , syncingFocus(false) { } @@ -109,6 +111,7 @@ public: QWindow fakeParent; uint usesNativeWidgets : 1; + uint syncingFocus : 1; }; @@ -272,8 +275,14 @@ bool QWindowContainer::eventFilter(QObject *o, QEvent *e) d->window = nullptr; } } else if (e->type() == QEvent::FocusIn) { - if (o == d->window) - setFocus(Qt::ActiveWindowFocusReason); + if (o == d->window) { + if (d->syncingFocus) { + d->syncingFocus = false; + return false; + } + if (!hasFocus()) + setFocus(Qt::ActiveWindowFocusReason); + } } return false; } @@ -323,7 +332,7 @@ bool QWindowContainer::event(QEvent *e) break; case QEvent::FocusIn: if (d->window->parent()) { - if (QGuiApplication::focusWindow() != d->window) { + if (QGuiApplication::focusWindow() != d->window && !d->syncingFocus) { QFocusEvent *event = static_cast(e); const auto reason = event->reason(); QWindowPrivate::FocusTarget target = QWindowPrivate::FocusTarget::Current; @@ -332,7 +341,14 @@ bool QWindowContainer::event(QEvent *e) else if (reason == Qt::BacktabFocusReason) target = QWindowPrivate::FocusTarget::Last; qt_window_private(d->window)->setFocusToTarget(target, reason); + d->syncingFocus = true; d->window->requestActivate(); + // In case the window doesn't get focused, + // we don't want to be stuck in syncingFocus forever. Reset it after a short delay. + QTimer::singleShot(200, this, [this]() { + Q_D(QWindowContainer); + d->syncingFocus = false; + }); } } break; diff --git a/local/recipes/qt/qtbase/source/src/widgets/styles/qfusionstyle.cpp b/local/recipes/qt/qtbase/source/src/widgets/styles/qfusionstyle.cpp index ed7c92844b..d546df7949 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/styles/qfusionstyle.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/styles/qfusionstyle.cpp @@ -347,7 +347,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, case PE_FrameTabBarBase: if (const QStyleOptionTabBarBase *tbb = qstyleoption_cast(option)) { - painter->save(); + QPainterStateGuard psg(painter); painter->setPen(outline.lighter(110)); switch (tbb->shape) { case QTabBar::RoundedNorth: { @@ -357,8 +357,8 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setClipRegion(region); painter->setPen(option->palette.light().color()); painter->drawLine(tbb->rect.topLeft() + QPoint(0, 1), tbb->rect.topRight() + QPoint(0, 1)); - } break; + } case QTabBar::RoundedWest: painter->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom()); break; @@ -373,23 +373,21 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, case QTabBar::TriangularEast: case QTabBar::TriangularWest: case QTabBar::TriangularSouth: - painter->restore(); QCommonStyle::drawPrimitive(elem, option, painter, widget); - return; + break; } - painter->restore(); } - return; + break; #endif // QT_CONFIG(tabbar) case PE_PanelScrollAreaCorner: { - painter->save(); + QPainterStateGuard psg(painter); QColor alphaOutline = outline; alphaOutline.setAlpha(180); painter->setPen(alphaOutline); painter->setBrush(option->palette.brush(QPalette::Window)); painter->drawRect(option->rect); - painter->restore(); - } break; + break; + } case PE_IndicatorArrowUp: case PE_IndicatorArrowDown: case PE_IndicatorArrowRight: @@ -414,16 +412,15 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, break; } qt_fusion_draw_arrow(arrow, painter, option, option->rect, arrowColor); - } break; - case PE_IndicatorItemViewItemCheck: - { + } + case PE_IndicatorItemViewItemCheck: { QStyleOptionButton button; button.QStyleOption::operator=(*option); button.state &= ~State_MouseOver; proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget); + break; } - return; case PE_IndicatorHeaderArrow: if (const QStyleOptionHeader *header = qstyleoption_cast(option)) { const QRect r = header->rect.translated(0, -2); @@ -445,8 +442,8 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); break; - case PE_IndicatorToolBarSeparator: - { + case PE_IndicatorToolBarSeparator: { + QPainterStateGuard psg(painter); const QRect &rect = option->rect; const int margin = 6; const QColor col = option->palette.window().color(); @@ -466,8 +463,8 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->drawLine(rect.left() + margin, rect.top() + offset + 1, rect.right() - margin, rect.top() + offset + 1); } - } break; + } case PE_Frame: { if (widget && widget->inherits("QComboBoxPrivateContainer")){ QStyleOption copy = *option; @@ -475,14 +472,15 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, proxy()->drawPrimitive(PE_PanelMenu, ©, painter, widget); break; } - painter->save(); + QPainterStateGuard psg(painter); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->translate(0.5, 0.5); painter->setPen(outline.lighter(108)); painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); - painter->restore(); } break; - case PE_FrameMenu: - painter->save(); - { + } + case PE_FrameMenu: { + QPainterStateGuard psg(painter); painter->setPen(outline); painter->drawRect(option->rect.adjusted(0, 0, -1, -1)); QColor frameLight = option->palette.window().color().lighter(160); @@ -497,11 +495,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setPen(frameShadow); painter->drawLine(frame.topRight(), frame.bottomRight()); painter->drawLine(frame.bottomLeft(), frame.bottomRight()); - } - painter->restore(); break; + } case PE_PanelButtonTool: - painter->save(); if ((option->state & State_Enabled || option->state & State_On) || !(option->state & State_AutoRaise)) { if (widget && widget->inherits("QDockWidgetTitleButton")) { if (option->state & State_MouseOver) @@ -510,7 +506,6 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, proxy()->drawPrimitive(PE_PanelButtonCommand, option, painter, widget); } } - painter->restore(); break; case PE_IndicatorDockWidgetResizeHandle: { @@ -521,9 +516,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, } break; case PE_FrameDockWidget: - case PE_FrameWindow: - { - painter->save(); + case PE_FrameWindow: { + QPainterStateGuard psg(painter); + const QRect &rect = option->rect; const QColor col = (elem == PE_FrameWindow) ? outline.darker(150) : option->palette.window().color().darker(120); @@ -538,16 +533,14 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, {rect.right() - 1, rect.top() + 1, rect.right() - 1, rect.bottom() - 1}}; painter->drawLines(lines, 2); - painter->restore(); break; } - case PE_FrameLineEdit: - { + case PE_FrameLineEdit: { + QPainterStateGuard psg(painter); + const QRect &r = option->rect; bool hasFocus = option->state & State_HasFocus; - painter->save(); - painter->setRenderHint(QPainter::Antialiasing, true); // ### highdpi painter bug. painter->translate(0.5, 0.5); @@ -566,13 +559,12 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setPen(QFusionStylePrivate::topShadow); painter->drawLine(QPoint(r.left() + 2, r.top() + 1), QPoint(r.right() - 2, r.top() + 1)); - painter->restore(); - - } break; + } case PE_IndicatorCheckBox: - painter->save(); if (const QStyleOptionButton *checkbox = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); + painter->setRenderHint(QPainter::Antialiasing, true); painter->translate(0.5, 0.5); const QRect rect = option->rect.adjusted(0, 0, -1, -1); @@ -630,11 +622,10 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->drawPath(path.translated(rect.topLeft())); } } - painter->restore(); break; - case PE_IndicatorRadioButton: - painter->save(); - { + case PE_IndicatorRadioButton: { + QPainterStateGuard psg(painter); + QColor pressedColor = mergedColors(option->palette.base().color(), option->palette.windowText().color(), 85); painter->setBrush((option->state & State_Sunken) ? pressedColor : option->palette.base().color()); painter->setRenderHint(QPainter::Antialiasing, true); @@ -662,9 +653,8 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, painter->setBrush(checkMarkColor); painter->drawPath(circle); } - } - painter->restore(); break; + } case PE_IndicatorToolBarHandle: { const QPoint center = option->rect.center(); @@ -695,7 +685,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, return; const QRect &rect = option->rect; - painter->save(); + QPainterStateGuard psg(painter); painter->setRenderHint(QPainter::Antialiasing, true); painter->translate(0.5, 0.5); QColor fillcolor = highlightedOutline; @@ -707,7 +697,6 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, gradient.setColorAt(1, fillcolor); painter->setBrush(gradient); painter->drawRoundedRect(rect.adjusted(0, 0, -1, -1), 1, 1); - painter->restore(); } break; case PE_PanelButtonCommand: @@ -780,22 +769,22 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, } } break; - case PE_FrameTabWidget: - painter->save(); - painter->fillRect(option->rect.adjusted(0, 0, -1, -1), d->tabFrameColor(option->palette)); + case PE_FrameTabWidget: { + QRect rect = option->rect.adjusted(0, 0, -1, -1); + painter->fillRect(rect, d->tabFrameColor(option->palette)); #if QT_CONFIG(tabwidget) if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(option)) { - QRect rect = option->rect.adjusted(0, 0, -1, -1); + QPainterStateGuard psg(painter); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->translate(0.5, 0.5); // Shadow outline if (twf->shape != QTabBar::RoundedSouth) { rect.adjust(0, 0, 0, -1); - QColor borderColor = outline.lighter(110); QColor alphaShadow(Qt::black); alphaShadow.setAlpha(15); painter->setPen(alphaShadow); painter->drawLine(option->rect.bottomLeft(), option->rect.bottomRight()); - painter->setPen(borderColor); } // outline @@ -808,20 +797,16 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, } #endif // QT_CONFIG(tabwidget) - painter->restore(); - break ; - + break; + } case PE_FrameStatusBarItem: break; case PE_PanelMenu: { - painter->save(); const QBrush menuBackground = option->palette.base().color().lighter(108); QColor borderColor = option->palette.window().color().darker(160); qDrawPlainRect(painter, option->rect, borderColor, 1, &menuBackground); - painter->restore(); - } break; - + } default: QCommonStyle::drawPrimitive(elem, option, painter, widget); break; @@ -839,8 +824,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio switch (element) { case CE_ComboBoxLabel: if (const QStyleOptionComboBox *cb = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); - painter->save(); painter->setClipRect(editRect); if (!cb->currentIcon.isNull()) { QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal @@ -866,11 +851,9 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio cb->palette, cb->state & State_Enabled, cb->currentText, cb->editable ? QPalette::Text : QPalette::ButtonText); } - painter->restore(); } break; - case CE_Splitter: - { + case CE_Splitter: { // Don't draw handle for single pixel splitters if (option->rect.width() > 1 && option->rect.height() > 1) { const QPoint center = option->rect.center(); @@ -892,9 +875,9 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio #if QT_CONFIG(rubberband) case CE_RubberBand: if (qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); const QRect &rect = option->rect; QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight); - painter->save(); QColor penColor = highlight.darker(120); penColor.setAlpha(180); painter->setPen(penColor); @@ -916,13 +899,11 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->setPen(innerLine); painter->drawRoundedRect(rect.adjusted(1, 1, -2, -2), 1, 1); } - painter->restore(); } break; #endif //QT_CONFIG(rubberband) - case CE_SizeGrip: - painter->save(); - { + case CE_SizeGrip: { + QPainterStateGuard psg(painter); const QPoint center = option->rect.center(); //draw grips for (int i = -6; i< 12 ; i += 3) { @@ -933,9 +914,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio } } } - } - painter->restore(); break; + } #if QT_CONFIG(toolbar) case CE_ToolBar: if (const QStyleOptionToolBar *toolBar = qstyleoption_cast(option)) { @@ -1060,8 +1040,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio break; #endif // QT_CONFIG(toolbar) case CE_DockWidgetTitle: - painter->save(); if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); bool verticalTitleBar = dwOpt->verticalTitleBar; QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget); @@ -1088,7 +1068,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio QPalette::WindowText); } } - painter->restore(); break; case CE_HeaderSection: // Draws the header in tables. @@ -1136,9 +1115,8 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio } } break; - case CE_ProgressBarGroove: - painter->save(); - { + case CE_ProgressBarGroove: { + QPainterStateGuard psg(painter); const QRect &rect = option->rect; painter->setRenderHint(QPainter::Antialiasing, true); painter->translate(0.5, 0.5); @@ -1156,13 +1134,12 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->setPen(QFusionStylePrivate::topShadow); painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1), QPoint(rect.right() - 1, rect.top() + 1)); - } - painter->restore(); break; + } case CE_ProgressBarContents: - painter->save(); - painter->setRenderHint(QPainter::Antialiasing, true); if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); + painter->setRenderHint(QPainter::Antialiasing, true); QRect rect = option->rect; painter->translate(rect.topLeft()); rect.translate(-rect.topLeft()); @@ -1223,17 +1200,17 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio gradient.setColorAt(1, highlightedGradientStopColor); painter->setBrush(gradient); - - painter->save(); - // 0.5 - half the width of a cosmetic pen (for vertical line below) - if (!complete && !indeterminate) - painter->setClipRect(QRectF(progressBar).adjusted(-1, -1, 0.5, 1)); - - QRect fillRect = progressBar; - if (!indeterminate && !complete) - fillRect.setWidth(std::min(fillRect.width() + 2, rect.width() - 1)); // avoid round borders at the right end - painter->drawRoundedRect(fillRect, 2, 2); - painter->restore(); + { + QPainterStateGuard psg2(painter, QPainterStateGuard::InitialState::NoSave); + QRect fillRect = progressBar; + // 0.5 - half the width of a cosmetic pen (for vertical line below) + if (!complete && !indeterminate) { + psg2.save(); + painter->setClipRect(QRectF(progressBar).adjusted(-1, -1, 0.5, 1)); + fillRect.setWidth(std::min(fillRect.width() + 2, rect.width() - 1)); // avoid round borders at the right end + } + painter->drawRoundedRect(fillRect, 2, 2); + } painter->setBrush(Qt::NoBrush); painter->setPen(QColor(255, 255, 255, 50)); @@ -1274,17 +1251,16 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->drawLine(progressBar.topRight() + QPoint(1, 1), progressBar.bottomRight() + QPoint(1, 0)); } } - painter->restore(); break; case CE_ProgressBarLabel: if (const QStyleOptionProgressBar *bar = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); const QRect &rect = bar->rect; QRect leftRect = rect; QRect rightRect = rect; QColor textColor = option->palette.text().color(); QColor alternateTextColor = d->highlightedText(option->palette); - painter->save(); const auto vertical = !(bar->state & QStyle::State_Horizontal); const auto inverted = bar->invertedAppearance; const auto reverse = (bar->direction == Qt::RightToLeft) ^ inverted; @@ -1321,14 +1297,11 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->setPen(firstIsAlternateColor ? textColor : alternateTextColor); painter->setClipRect(leftRect); painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter)); - - painter->restore(); } break; case CE_MenuBarItem: - painter->save(); - if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) - { + if (const QStyleOptionMenuItem *mbi = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); const QRect &rect = option->rect; QStyleOptionMenuItem item = *mbi; item.rect = mbi->rect.adjusted(0, 1, 0, -3); @@ -1360,12 +1333,11 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->drawLine(rect.bottomLeft(), rect.bottomRight()); } } - painter->restore(); break; case CE_MenuItem: - painter->save(); // Draws one item in a popup menu. if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { int w = 0; const int margin = int(QStyleHelper::dpiScaled(5, option)); @@ -1382,7 +1354,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio qreal y = menuItem->rect.center().y() + 0.5f; painter->drawLine(QPointF(menuItem->rect.left() + margin + (reverse ? 0 : w), y), QPointF(menuItem->rect.right() - margin - (reverse ? w : 0), y)); - painter->restore(); break; } const bool selected = menuItem->state & State_Selected && menuItem->state & State_Enabled; @@ -1517,7 +1488,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio const QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect); QStringView s(menuitem->text); if (!s.isEmpty()) { // draw text - p->save(); + QPainterStateGuard psg(painter); const qsizetype tabIndex = s.indexOf(u'\t'); int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget)) @@ -1558,7 +1529,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio p->setPen(discol); } p->drawText(vTextRect, text_flags, textToDraw); - p->restore(); } // Arrow @@ -1578,7 +1548,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio proxy()->drawPrimitive(arrow, &newMI, painter, widget); } } - painter->restore(); break; case CE_MenuHMargin: case CE_MenuVMargin: @@ -1593,22 +1562,20 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio proxy()->drawControl(CE_PushButtonLabel, &subopt, painter, widget); } break; - case CE_MenuBarEmptyArea: - painter->save(); - { + case CE_MenuBarEmptyArea: { + QPainterStateGuard psg(painter); const QRect &rect = option->rect; painter->fillRect(rect, option->palette.window()); QColor shadow = mergedColors(option->palette.window().color().darker(120), d->outline(option->palette).lighter(140), 60); painter->setPen(shadow); painter->drawLine(rect.bottomLeft(), rect.bottomRight()); - } - painter->restore(); break; + } #if QT_CONFIG(tabbar) case CE_TabBarTabShape: - painter->save(); if (const QStyleOptionTab *tab = qstyleoption_cast(option)) { + QPainterStateGuard psg(painter); bool rtlHorTabs = (tab->direction == Qt::RightToLeft && (tab->shape == QTabBar::RoundedNorth @@ -1647,7 +1614,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->setTransform(rotMatrix, true); break; default: - painter->restore(); QCommonStyle::drawControl(element, tab, painter, widget); return; } @@ -1677,15 +1643,16 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->setPen(outline.lighter(110)); } - QRect drawRect = rect.adjusted(0, selected ? 0 : 2, 0, 3); - painter->save(); - painter->setClipRect(rect.adjusted(-1, -1, 1, selected ? -2 : -3)); - painter->setBrush(fillGradient); - painter->drawRoundedRect(drawRect.adjusted(0, 0, -1, -1), 2.0, 2.0); - painter->setBrush(Qt::NoBrush); - painter->setPen(QFusionStylePrivate::innerContrastLine); - painter->drawRoundedRect(drawRect.adjusted(1, 1, -2, -1), 2.0, 2.0); - painter->restore(); + { + QPainterStateGuard psg(painter); + QRect drawRect = rect.adjusted(0, selected ? 0 : 2, 0, 3); + painter->setClipRect(rect.adjusted(-1, -1, 1, selected ? -2 : -3)); + painter->setBrush(fillGradient); + painter->drawRoundedRect(drawRect.adjusted(0, 0, -1, -1), 2.0, 2.0); + painter->setBrush(Qt::NoBrush); + painter->setPen(QFusionStylePrivate::innerContrastLine); + painter->drawRoundedRect(drawRect.adjusted(1, 1, -2, -1), 2.0, 2.0); + } if (selected) { painter->fillRect(rect.left() + 1, rect.bottom() - 1, rect.width() - 2, rect.bottom() - 1, tabFrameColor); @@ -1694,7 +1661,6 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio painter->fillRect(QRect(rect.bottomRight() + QPoint(-1, -1), QSize(1, 1)), QFusionStylePrivate::innerContrastLine); } } - painter->restore(); break; #endif //QT_CONFIG(tabbar) default: @@ -2142,15 +2108,17 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption case CC_ScrollBar: if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) { QPainterStateGuard psg(painter); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->translate(0.5, 0.5); + + auto *prx = proxy(); bool horizontal = scrollBar->orientation == Qt::Horizontal; bool sunken = scrollBar->state & State_Sunken; - QRect scrollBarSubLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSubLine, widget); - QRect scrollBarAddLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarAddLine, widget); - QRect scrollBarSlider = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget); - QRect scrollBarGroove = proxy()->subControlRect(control, scrollBar, SC_ScrollBarGroove, widget); + QRect scrollBarSlider = prx->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget); + QRect scrollBarGroove = prx->subControlRect(control, scrollBar, SC_ScrollBarGroove, widget); - QRect rect = option->rect; + const QRect &rect = option->rect; QColor alphaOutline = d->outline(option->palette); alphaOutline.setAlpha(180); @@ -2161,12 +2129,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption const bool isDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128; // Paint groove - if (scrollBar->activeSubControls && scrollBar->subControls & SC_ScrollBarGroove) { - QLinearGradient gradient(rect.center().x(), rect.top(), - rect.center().x(), rect.bottom()); - if (!horizontal) - gradient = QLinearGradient(rect.left(), rect.center().y(), - rect.right(), rect.center().y()); + if (scrollBar->subControls & SC_ScrollBarGroove) { + const auto center = scrollBarGroove.center(); + auto gradient = horizontal ? QLinearGradient(center.x(), scrollBarGroove.top(), + center.x(), scrollBarGroove.bottom()) + : QLinearGradient(scrollBarGroove.left(), center.y(), + scrollBarGroove.right(), center.y()); + if (!isDarkBg) { QColor buttonColor = d->buttonColor(option->palette); gradient.setColorAt(0, buttonColor.darker(107)); @@ -2181,7 +2150,6 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption } painter->fillRect(rect, gradient); - painter->setPen(Qt::NoPen); painter->setPen(alphaOutline); if (horizontal) painter->drawLine(rect.topLeft(), rect.topRight()); @@ -2195,11 +2163,11 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption painter->drawRect(scrollBarGroove.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1)); } - QLinearGradient gradient(scrollBarSlider.center().x(), scrollBarSlider.top(), - scrollBarSlider.center().x(), scrollBarSlider.bottom()); - if (!horizontal) - gradient = QLinearGradient(scrollBarSlider.left(), scrollBarSlider.center().y(), - scrollBarSlider.right(), scrollBarSlider.center().y()); + const auto center = scrollBarSlider.center(); + auto gradient = horizontal ? QLinearGradient(center.x(), scrollBarSlider.top(), + center.x(), scrollBarSlider.bottom()) + : QLinearGradient(scrollBarSlider.left(), center.y(), + scrollBarSlider.right(), center.y()); QLinearGradient highlightedGradient = gradient; @@ -2216,7 +2184,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption // Paint slider if (scrollBar->subControls & SC_ScrollBarSlider) { painter->setPen(alphaOutline); - if (option->state & State_Sunken && scrollBar->activeSubControls & SC_ScrollBarSlider) + if (sunken && scrollBar->activeSubControls & SC_ScrollBarSlider) painter->setBrush(midColor2); else if (option->state & State_MouseOver && scrollBar->activeSubControls & SC_ScrollBarSlider) painter->setBrush(highlightedGradient); @@ -2233,55 +2201,38 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption painter->drawRect(scrollBarSlider.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1)); } + auto drawUpDown = [&](SubControl sc, Qt::ArrowType arrowType) { + const QRect subRect = prx->subControlRect(control, scrollBar, sc, widget); + painter->setBrush(Qt::NoBrush); + painter->setPen(alphaOutline); + painter->drawRect(subRect); + if (scrollBar->activeSubControls.testFlag(sc)) { + if (sunken) + painter->setBrush(gradientStopColor); + else + painter->setBrush(highlightedGradient); + } else { + painter->setBrush(gradient); + } + painter->setPen(QFusionStylePrivate::innerContrastLine); + painter->drawRect(subRect.adjusted(1, 1, -1, -1)); + + qt_fusion_draw_arrow(arrowType, painter, option, subRect, + arrowColor); + }; // The SubLine (up/left) buttons if (scrollBar->subControls & SC_ScrollBarSubLine) { - if ((scrollBar->activeSubControls & SC_ScrollBarSubLine) && sunken) - painter->setBrush(gradientStopColor); - else if ((scrollBar->activeSubControls & SC_ScrollBarSubLine)) - painter->setBrush(highlightedGradient); - else - painter->setBrush(gradient); - - const QRect upRect = scrollBarSubLine.adjusted(0, 0, -1, -1); - painter->setPen(Qt::NoPen); - painter->drawRect(upRect.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0)); - painter->setPen(alphaOutline); - painter->drawRect(upRect); - - painter->setBrush(Qt::NoBrush); - painter->setPen(QFusionStylePrivate::innerContrastLine); - painter->drawRect(upRect.adjusted(1, 1, -1, -1)); - - // Arrows Qt::ArrowType arrowType = Qt::UpArrow; if (option->state & State_Horizontal) arrowType = option->direction == Qt::LeftToRight ? Qt::LeftArrow : Qt::RightArrow; - qt_fusion_draw_arrow(arrowType, painter, option, upRect.adjusted(1, 1, 0, 0), arrowColor); + drawUpDown(SC_ScrollBarSubLine, arrowType); } - // The AddLine (down/right) button if (scrollBar->subControls & SC_ScrollBarAddLine) { - if ((scrollBar->activeSubControls & SC_ScrollBarAddLine) && sunken) - painter->setBrush(gradientStopColor); - else if ((scrollBar->activeSubControls & SC_ScrollBarAddLine)) - painter->setBrush(midColor2); - else - painter->setBrush(gradient); - - const QRect downRect = scrollBarAddLine.adjusted(0, 0, -1, -1); - painter->setPen(Qt::NoPen); - painter->drawRect(downRect.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0)); - painter->setPen(alphaOutline); - painter->drawRect(downRect); - - painter->setBrush(Qt::NoBrush); - painter->setPen(QFusionStylePrivate::innerContrastLine); - painter->drawRect(downRect.adjusted(1, 1, -1, -1)); - Qt::ArrowType arrowType = Qt::DownArrow; if (option->state & State_Horizontal) arrowType = option->direction == Qt::LeftToRight ? Qt::RightArrow : Qt::LeftArrow; - qt_fusion_draw_arrow(arrowType, painter, option, downRect.adjusted(1, 1, 0, 0), arrowColor); + drawUpDown(SC_ScrollBarAddLine, arrowType); } } break; diff --git a/local/recipes/qt/qtbase/source/src/widgets/styles/qstylehelper.cpp b/local/recipes/qt/qtbase/source/src/widgets/styles/qstylehelper.cpp index 6a1556f2f3..b1d559c2e0 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/styles/qstylehelper.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/styles/qstylehelper.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/local/recipes/qt/qtbase/source/src/widgets/styles/qstyleoption.h b/local/recipes/qt/qtbase/source/src/widgets/styles/qstyleoption.h index 4f199d2b0a..8ff1d04519 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/styles/qstyleoption.h +++ b/local/recipes/qt/qtbase/source/src/widgets/styles/qstyleoption.h @@ -341,7 +341,7 @@ public: #if QT_DEPRECATED_SINCE(6, 11) Margin Q_DECL_ENUMERATOR_DEPRECATED_X("Not used anywhere"), #endif - EmptyArea }; + EmptyArea = TearOff + 2 }; enum CheckType { NotCheckable, Exclusive, NonExclusive }; MenuItemType menuItemType; diff --git a/local/recipes/qt/qtbase/source/src/widgets/styles/qstylesheetstyle.cpp b/local/recipes/qt/qtbase/source/src/widgets/styles/qstylesheetstyle.cpp index e140321342..13f8d293cb 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/styles/qstylesheetstyle.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/styles/qstylesheetstyle.cpp @@ -3942,7 +3942,17 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if (mi.menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow PrimitiveElement arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; QRenderRule subRule2 = renderRule(w, opt, PseudoElement_MenuRightArrow); - mi.rect = positionRect(w, subRule, subRule2, PseudoElement_MenuRightArrow, opt->rect, mi.direction); + if (subRule2.hasContentsSize()) { + mi.rect = positionRect(w, subRule, subRule2, PseudoElement_MenuRightArrow, opt->rect, mi.direction); + } else { + // Derive arrow size from the item height + int dim = opt->rect.height() / 2; + QRect arrowRect(0, 0, dim, dim); + // Right-align arrow + arrowRect.moveCenter(QPoint(opt->rect.right() - dim, opt->rect.center().y())); + mi.rect = visualRect(opt->direction, opt->rect, arrowRect); + } + drawPrimitive(arrow, &mi, p, w); } } else if (!mi.icon.isNull() && hasStyleRule(w, PseudoElement_MenuIcon)) { diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractbutton.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractbutton.cpp index 729ea884cb..67a816bd2b 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractbutton.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractbutton.cpp @@ -327,7 +327,10 @@ void QAbstractButtonPrivate::init() { Q_Q(QAbstractButton); - q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy, nullptr, q))); + // Query focus policy. Don't pass the QWidget pointer since QStyleSheetStyle will + // (if in use) cache it derive incorrect style metrics from it. + q->setFocusPolicy(Qt::FocusPolicy(q->style()->styleHint(QStyle::SH_Button_FocusPolicy, + nullptr, nullptr))); q->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, controlType)); q->setAttribute(Qt::WA_WState_OwnSizePolicy, false); q->setForegroundRole(QPalette::ButtonText); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox.cpp index 00718d6084..e620a8451f 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox.cpp @@ -19,31 +19,24 @@ #include #include #include +#include #if QT_CONFIG(menu) #include #endif -#include -#include #include -#include #if QT_CONFIG(accessibility) # include #endif #include -//#define QABSTRACTSPINBOX_QSBDEBUG -#ifdef QABSTRACTSPINBOX_QSBDEBUG -# define QASBDEBUG qDebug -#else -# define QASBDEBUG if (false) qDebug -#endif - QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; using namespace std::chrono_literals; +Q_STATIC_LOGGING_CATEGORY(lcWidgetAbstractSpinBox, "qt.widgets.qabstractspinbox") + /*! \class QAbstractSpinBox \brief The QAbstractSpinBox class provides a spinbox and a line edit to @@ -648,7 +641,8 @@ void QAbstractSpinBox::stepBy(int steps) default: singleStep = d->singleStep; } - d->setValue(d->bound(d->value + (singleStep * steps), old, steps), e); + const auto newVal = d->bound(d->value + (singleStep * steps), old, steps); + d->setValue(d->roundValue(newVal), e); } else if (e == AlwaysEmit) { d->emitSignals(e, old); } @@ -1781,6 +1775,11 @@ void QAbstractSpinBoxPrivate::setValue(const QVariant &val, EmitPolicy ep, } } +QVariant QAbstractSpinBoxPrivate::roundValue(const QVariant &val) const +{ + return val; +} + /*! \internal @@ -1910,7 +1909,8 @@ void QAbstractSpinBoxPrivate::interpret(EmitPolicy ep) if (q->validate(tmp, pos) != QValidator::Acceptable) { const QString copy = tmp; q->fixup(tmp); - QASBDEBUG() << "QAbstractSpinBoxPrivate::interpret() text '" + qDebug(lcWidgetAbstractSpinBox) + << "QAbstractSpinBoxPrivate::interpret() text '" << edit->displayText() << "' >> '" << copy << '\'' << "' >> '" << tmp << '\''; diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox_p.h index db9b5488ac..d0a010f02c 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qabstractspinbox_p.h @@ -69,6 +69,7 @@ public: virtual void setRange(const QVariant &min, const QVariant &max); void setValue(const QVariant &val, EmitPolicy ep, bool updateEdit = true); virtual QVariant bound(const QVariant &val, const QVariant &old = QVariant(), int steps = 0) const; + virtual QVariant roundValue(const QVariant &val) const; virtual void updateEdit(); virtual void emitSignals(EmitPolicy ep, const QVariant &old); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockarealayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockarealayout.cpp index 2a94823856..fb3930d202 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockarealayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockarealayout.cpp @@ -35,7 +35,14 @@ Q_LOGGING_CATEGORY(lcQpaDockWidgets, "qt.widgets.dockwidgets"); // qmainwindow.cpp extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); -enum { StateFlagVisible = 1, StateFlagFloating = 2 }; +enum class StateFlag +{ + Visible = 0x01, + Floating = 0x02, + FloatingTabs = 0x04, + Closed = 0x08, +}; +Q_DECLARE_FLAGS(StateFlags, StateFlag); /****************************************************************************** ** QPlaceHolderItem @@ -202,11 +209,32 @@ QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem &item) } else if (item.subinfo) { dbg << "subInfo(" << item.subinfo << "->(" << item.subinfo->item_list << ")"; } else if (item.placeHolderItem) { - dbg << "placeHolderItem(" << item.placeHolderItem << ")"; + dbg << "placeHolderItem(" << item.placeHolderItem + << "objectName:" << item.placeHolderItem->objectName << "; " + << "hidden:" << item.placeHolderItem->hidden << "; " + << "window:" << item.placeHolderItem->window << "; " + << "topLevelRect:" << item.placeHolderItem->topLevelRect << ")"; } dbg << ")"; return dbg; } + +QDebug operator<<(QDebug dbg, StateFlags flags) +{ + QDebugStateSaver saver(dbg); + dbg.nospace().noquote(); + QStringList f; + if (flags.testFlag(StateFlag::Visible)) + f << QLatin1StringView("Visible"); + if (flags.testFlag(StateFlag::Floating)) + f << QLatin1StringView("Floating"); + if (flags.testFlag(StateFlag::FloatingTabs)) + f << QLatin1StringView("FloatingTabs"); + if (flags.testFlag(StateFlag::Closed)) + f << QLatin1StringView("Closed"); + dbg << "StateFlags(" << f.join(u'|') << ")"; + return dbg; +} #endif // QT_NO_DEBUG_STREAM /****************************************************************************** @@ -1837,6 +1865,15 @@ void QDockAreaLayoutInfo::deleteAllLayoutItems() void QDockAreaLayoutInfo::saveState(QDataStream &stream) const { + qsizetype cnt = 0; + for (qsizetype i = 0; i < item_list.size(); ++i) { + const QDockAreaLayoutItem &item = item_list.at(i); + if (item.widgetItem && qobject_cast(item.widgetItem->widget())) { + continue; + } + ++cnt; + } + #if QT_CONFIG(tabbar) if (tabbed) { stream << (uchar) TabMarker; @@ -1857,27 +1894,38 @@ void QDockAreaLayoutInfo::saveState(QDataStream &stream) const stream << (uchar) SequenceMarker; } - stream << (uchar) o << int(item_list.size()); + stream << static_cast(o) << static_cast(cnt); for (int i = 0; i < item_list.size(); ++i) { const QDockAreaLayoutItem &item = item_list.at(i); if (item.widgetItem != nullptr) { - stream << (uchar) WidgetMarker; QWidget *w = item.widgetItem->widget(); + if (qobject_cast(w)) { + qCDebug(lcQpaDockWidgets) << "Ignoring dock widget group window" << w; + continue; + } + stream << (uchar) WidgetMarker; QString name = w->objectName(); if (Q_UNLIKELY(name.isEmpty())) { - qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%ls;", - w, qUtf16Printable(w->windowTitle())); + qWarning() << "QMainWindow::saveState(): 'objectName' not set for" + << w << qUtf16Printable(w->windowTitle()); } stream << name; - uchar flags = 0; + StateFlags flags; if (!w->isHidden()) - flags |= StateFlagVisible; + flags.setFlag(StateFlag::Visible); if (w->isWindow()) - flags |= StateFlagFloating; - stream << flags; + flags.setFlag(StateFlag::Floating); + if (qobject_cast(w->parent())) + flags.setFlag(StateFlag::FloatingTabs); + if (auto *dw = qobject_cast(w)) { + const auto priv = static_cast(QObjectPrivate::get(dw)); + flags.setFlag(StateFlag::Closed, priv->closed); + } + stream << static_cast(flags.toInt()); + qCDebug(lcQpaDockWidgets) << "Saving state for dock widget:" << w->objectName() << flags; if (w->isWindow()) { const QRect geometry = w->geometry(); stream << geometry.x() << geometry.y() << geometry.width() << geometry.height(); @@ -1888,12 +1936,13 @@ void QDockAreaLayoutInfo::saveState(QDataStream &stream) const } else if (item.placeHolderItem != nullptr) { stream << (uchar) WidgetMarker; stream << item.placeHolderItem->objectName; - uchar flags = 0; + StateFlags flags; if (!item.placeHolderItem->hidden) - flags |= StateFlagVisible; + flags.setFlag(StateFlag::Visible); if (item.placeHolderItem->window) - flags |= StateFlagFloating; - stream << flags; + flags.setFlag(StateFlag::Floating); + qCDebug(lcQpaDockWidgets) << "Saving state for placeholder item:" << item << flags; + stream << static_cast(flags.toInt()); if (item.placeHolderItem->window) { QRect r = item.placeHolderItem->topLevelRect; stream << r.x() << r.y() << r.width() << r.height(); @@ -1919,8 +1968,11 @@ static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos) return Qt::NoDockWidgetArea; } -bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList &widgets, bool testing) +bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList &widgets, QInternal::CallMode callMode) { + const bool testing = callMode == QInternal::Testing; + const QLatin1StringView debugCallMode = testing ? QLatin1StringView("(testing)") + : QLatin1StringView("(restoring)"); uchar marker; stream >> marker; if (marker != TabMarker && marker != SequenceMarker) @@ -1946,8 +1998,9 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList stream >> nextMarker; if (nextMarker == WidgetMarker) { QString name; - uchar flags; - stream >> name >> flags; + uchar f; + stream >> name >> f; + StateFlags flags(f); if (name.isEmpty()) { int dummy; stream >> dummy >> dummy >> dummy >> dummy; @@ -1955,7 +2008,7 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList } QDockWidget *widget = nullptr; - for (int j = 0; j < widgets.size(); ++j) { + for (qsizetype j = 0; j < widgets.size(); ++j) { if (widgets.at(j)->objectName() == name) { widget = widgets.takeAt(j); break; @@ -1966,8 +2019,8 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList QPlaceHolderItem *placeHolder = new QPlaceHolderItem; QDockAreaLayoutItem item(placeHolder); - placeHolder->window = flags & StateFlagFloating; - placeHolder->hidden = !(flags & StateFlagVisible); + placeHolder->window = flags.testFlag(StateFlag::Floating); + placeHolder->hidden = !flags.testFlag(StateFlag::Visible); if (placeHolder->window) { int x, y, w, h; stream >> x >> y >> w >> h; @@ -1979,27 +2032,25 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList if (item.size != -1) item.flags |= QDockAreaLayoutItem::KeepSize; placeHolder->objectName = std::move(name); + qCDebug(lcQpaDockWidgets) << "Restoring placeholder" << item << debugCallMode << flags; if (!testing) item_list.append(item); } else { + if (flags.testFlag(StateFlag::FloatingTabs)) + qCDebug(lcQpaDockWidgets) << "Found floating tab:" << name << flags << debugCallMode; QDockAreaLayoutItem item(new QDockWidgetItem(widget)); - if (flags & StateFlagFloating) { - bool drawer = false; - + if (flags.testFlag(StateFlag::Floating)) { if (!testing) { widget->hide(); - if (!drawer) - widget->setFloating(true); + widget->setFloating(true); } int x, y, w, h; stream >> x >> y >> w >> h; - if (!testing) - widget->setGeometry(QDockAreaLayout::constrainedRect(QRect(x, y, w, h), widget)); - if (!testing) { - widget->setVisible(flags & StateFlagVisible); + widget->setGeometry(QDockAreaLayout::constrainedRect(QRect(x, y, w, h), widget)); + widget->setVisible(flags.testFlag(StateFlag::Visible)); item_list.append(item); } } else { @@ -2007,11 +2058,16 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList stream >> item.pos >> item.size >> dummy >> dummy; if (!testing) { item_list.append(item); - widget->setFloating(false); - widget->setVisible(flags & StateFlagVisible); + if (flags.testFlag(StateFlag::Closed)) { + widget->close(); + } else { + widget->setFloating(false); + widget->setVisible(flags.testFlag(StateFlag::Visible)); + } emit widget->dockLocationChanged(toDockWidgetArea(dockPos)); } } + qCDebug(lcQpaDockWidgets) << "Restoring QDockWidget" << item << flags << debugCallMode; if (testing) { //was it is not really added to the layout, we need to delete the object here delete item.widgetItem; @@ -2026,6 +2082,7 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow)); stream >> item.pos >> item.size >> dummy >> dummy; + qCDebug(lcQpaDockWidgets) << "Restoring separator item" << item << debugCallMode; //we need to make sure the element is in the list so the dock widget can eventually be docked correctly if (!testing) item_list.append(item); @@ -2033,7 +2090,7 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList //here we need to make sure we change the item in the item_list QDockAreaLayoutItem &lastItem = testing ? item : item_list.last(); - if (!lastItem.subinfo->restoreState(stream, widgets, testing)) + if (!lastItem.subinfo->restoreState(stream, widgets, callMode)) return false; } else { @@ -2419,10 +2476,10 @@ void QDockAreaLayout::saveState(QDataStream &stream) const stream << static_cast(corners[i]); } -bool QDockAreaLayout::restoreState(QDataStream &stream, const QList &_dockwidgets, bool testing) +bool QDockAreaLayout::restoreState(QDataStream &stream, const QList &_dockwidgets, QInternal::CallMode callMode) { QList dockwidgets = _dockwidgets; - + const bool testing = callMode == QInternal::Testing; int cnt; stream >> cnt; for (int i = 0; i < cnt; ++i) { @@ -2433,7 +2490,7 @@ bool QDockAreaLayout::restoreState(QDataStream &stream, const QList &widgets, bool testing); + bool restoreState(QDataStream &stream, QList &widgets, QInternal::CallMode); void fitItems(); bool expansive(Qt::Orientation o) const; @@ -216,7 +216,7 @@ public: enum { DockWidgetStateMarker = 0xfd, FloatingDockWidgetTabMarker = 0xf9 }; static QRect constrainedRect(QRect rect, QWidget *widget); void saveState(QDataStream &stream) const; - bool restoreState(QDataStream &stream, const QList &widgets, bool testing = false); + bool restoreState(QDataStream &stream, const QList &_dockWidgets, QInternal::CallMode callMode); QList indexOfPlaceHolder(const QString &objectName) const; QList indexOf(const QWidget *dockWidget) const; diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget.cpp index 7e3605fe57..117c72f0d0 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget.cpp @@ -782,7 +782,7 @@ void QDockWidgetPrivate::startDrag(DragScope scope) } if (state->ctrlDrag) - layout->restore(); + layout->restore(QInternal::KeepSavedState); state->dragging = true; @@ -829,7 +829,7 @@ void QDockWidgetPrivate::endDrag(EndDragMode mode) delete state->widgetItem; state->widgetItem = nullptr; } - mwLayout->restore(); + mwLayout->restore(QInternal::KeepSavedState); QDockWidgetLayout *dwLayout = qobject_cast(layout); if (!dwLayout->nativeWindowDeco()) { // get rid of the X11BypassWindowManager window flag and activate the resizer @@ -1609,6 +1609,8 @@ void QDockWidget::closeEvent(QCloseEvent *event) const QMainWindow *win = qobject_cast(parentWidget()); const bool canClose = (d->features & DockWidgetClosable) || (!win || !win->isVisible()); + if (canClose) + d->closed = true; event->setAccepted(canClose); } @@ -1664,6 +1666,7 @@ bool QDockWidget::event(QEvent *event) break; case QEvent::Show: { d->toggleViewAction->setChecked(true); + d->closed = false; QPoint parentTopLeft(0, 0); if (isWindow()) { const QScreen *screen = d->associatedScreen(); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget_p.h index 9c0498353c..3a3ac939ed 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qdockwidget_p.h @@ -95,6 +95,7 @@ public: QRect undockedGeometry; QString fixedWindowTitle; QString dockedWindowTitle; + bool closed = false; bool mousePressEvent(QMouseEvent *event); bool mouseDoubleClickEvent(QMouseEvent *event); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qfontcombobox.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qfontcombobox.cpp index 1b7fe133aa..4835875273 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qfontcombobox.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qfontcombobox.cpp @@ -425,8 +425,8 @@ QFontComboBox::QFontComboBox(QWidget *parent) */ QFontComboBox::~QFontComboBox() { - Q_D(const QFontComboBox); - for (const QMetaObject::Connection &connection : d->connections) + Q_D(QFontComboBox); + for (QMetaObject::Connection &connection : d->connections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qlabel.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qlabel.cpp index a2171eb347..59a6eeeea2 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qlabel.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qlabel.cpp @@ -931,10 +931,10 @@ void QLabel::keyPressEvent(QKeyEvent *ev) bool QLabel::event(QEvent *e) { Q_D(QLabel); - QEvent::Type type = e->type(); + switch (e->type()) { #ifndef QT_NO_SHORTCUT - if (type == QEvent::Shortcut) { + case QEvent::Shortcut: { QShortcutEvent *se = static_cast(e); if (se->shortcutId() == d->shortcutId) { QWidget *w = d->buddy; @@ -951,21 +951,30 @@ bool QLabel::event(QEvent *e) window()->setAttribute(Qt::WA_KeyboardFocusChange); return true; } - } else + break; + } #endif - if (type == QEvent::Resize) { + case QEvent::Resize: if (d->control) d->textLayoutDirty = true; - } else if (e->type() == QEvent::StyleChange + break; + case QEvent::StyleChange: #ifdef Q_OS_MAC - || e->type() == QEvent::MacSizeChange + case QEvent::MacSizeChange: #endif - ) { d->setLayoutItemMargins(QStyle::SE_LabelLayoutItem); d->updateLabel(); - } else if (type == QEvent::Polish) { + break; + case QEvent::Polish: if (d->needTextControl()) d->ensureTextControl(); + break; + case QEvent::Enter: + case QEvent::Leave: + d->sendControlEvent(e); + break; + default: + break; } return QFrame::event(e); @@ -1305,7 +1314,7 @@ void QLabelPrivate::clearContents() shortcutId = 0; #endif #if QT_CONFIG(movie) - for (const auto &conn : std::as_const(movieConnections)) + for (auto &conn : movieConnections) QObject::disconnect(conn); movie = nullptr; #endif diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindow.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindow.cpp index ef813726f5..9964dc782a 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindow.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindow.cpp @@ -1259,7 +1259,7 @@ bool QMainWindow::event(QEvent *event) case QEvent::DragLeave: if (!d->layout->draggingWidget) break; - d->layout->hover(d->layout->draggingWidget, pos() - QPoint(-1, -1)); + d->layout->hover(d->layout->draggingWidget, pos() - QPoint(1, 1)); return true; #endif default: diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout.cpp index 575752344b..da216294b6 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout.cpp @@ -673,8 +673,11 @@ void QDockWidgetGroupWindow::childEvent(QChildEvent *event) destroyIfSingleItemLeft(); break; case QEvent::ChildAdded: - if (auto *dockWidget = qobject_cast(event->child())) + if (auto *dockWidget = qobject_cast(event->child())) { dockWidget->installEventFilter(this); + if (objectName().isEmpty()) + setObjectName(dockWidget->objectName() + QLatin1String("_groupWindow")); + } break; default: break; @@ -1249,21 +1252,6 @@ void QMainWindowLayoutState::saveState(QDataStream &stream) const #endif } -template -static QList findChildrenHelper(const QObject *o) -{ - const QObjectList &list = o->children(); - QList result; - - for (int i=0; i < list.size(); ++i) { - if (T t = qobject_cast(list[i])) { - result.append(t); - } - } - - return result; -} - #if QT_CONFIG(dockwidget) static QList allMyDockWidgets(const QWidget *mainWindow) { @@ -1295,10 +1283,9 @@ bool QMainWindowLayoutState::checkFormat(QDataStream &stream) case QToolBarAreaLayout::ToolBarStateMarker: case QToolBarAreaLayout::ToolBarStateMarkerEx: { - QList toolBars = findChildrenHelper(mainWindow); - if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, true /*testing*/)) { - return false; - } + const auto toolBars = mainWindow->findChildren(); + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, QInternal::Testing)) + return false; } break; #endif // QT_CONFIG(toolbar) @@ -1307,9 +1294,8 @@ bool QMainWindowLayoutState::checkFormat(QDataStream &stream) case QDockAreaLayout::DockWidgetStateMarker: { const auto dockWidgets = allMyDockWidgets(mainWindow); - if (!dockAreaLayout.restoreState(stream, dockWidgets, true /*testing*/)) { + if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Testing)) return false; - } } break; #if QT_CONFIG(tabbar) @@ -1319,7 +1305,7 @@ bool QMainWindowLayoutState::checkFormat(QDataStream &stream) stream >> geom; QDockAreaLayoutInfo info; auto dockWidgets = allMyDockWidgets(mainWindow); - if (!info.restoreState(stream, dockWidgets, true /* testing*/)) + if (!info.restoreState(stream, dockWidgets, QInternal::Testing)) return false; } break; @@ -1363,32 +1349,46 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream, { #if QT_CONFIG(dockwidget) case QDockAreaLayout::DockWidgetStateMarker: - { - const auto dockWidgets = allMyDockWidgets(mainWindow); - if (!dockAreaLayout.restoreState(stream, dockWidgets)) - return false; + { + const auto dockWidgets = allMyDockWidgets(mainWindow); + if (!dockAreaLayout.restoreState(stream, dockWidgets, QInternal::Live)) + return false; - for (int i = 0; i < dockWidgets.size(); ++i) { - QDockWidget *w = dockWidgets.at(i); - QList path = dockAreaLayout.indexOf(w); - if (path.isEmpty()) { - QList oldPath = oldState.dockAreaLayout.indexOf(w); - if (oldPath.isEmpty()) { - continue; - } - QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath); - if (info == nullptr) { - continue; - } - info->add(w); + for (auto *w : dockWidgets) { + const QList path = dockAreaLayout.indexOf(w); + if (path.isEmpty()) { + QList oldPath = oldState.dockAreaLayout.indexOf(w); + if (oldPath.isEmpty()) + continue; + QDockAreaLayoutInfo *info = dockAreaLayout.info(oldPath); + if (info == nullptr) { + continue; } + info->add(w); } } - break; + } + break; #if QT_CONFIG(tabwidget) case QDockAreaLayout::FloatingDockWidgetTabMarker: { auto dockWidgets = allMyDockWidgets(mainWindow); + // dissolve all floating tabs first. + for (auto *dockWidget : std::as_const(dockWidgets)) { + QPointer gw = qobject_cast(dockWidget->parent()); + if (!gw) + continue; + const bool visible = gw->isVisible(); + gw->reparentToMainWindow(dockWidget); + dockWidget->setFloating(true); + dockWidget->setVisible(visible); + } +#ifndef QT_NO_DEBUG + const auto groupWindows = mainWindow->findChildren(); + for (auto *gw : groupWindows) + Q_ASSERT(gw->dockWidgets().isEmpty()); +#endif + QDockWidgetGroupWindow* floatingTab = qt_mainwindow_layout(mainWindow)->createTabbedDockWindow(); *floatingTab->layoutInfo() = QDockAreaLayoutInfo( &dockAreaLayout.sep, QInternal::LeftDock, // FIXME: DockWidget doesn't save original docking area @@ -1396,7 +1396,7 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream, QRect geometry; stream >> geometry; QDockAreaLayoutInfo *info = floatingTab->layoutInfo(); - if (!info->restoreState(stream, dockWidgets, false)) + if (!info->restoreState(stream, dockWidgets, QInternal::Live)) return false; geometry = QDockAreaLayout::constrainedRect(geometry, floatingTab); floatingTab->move(geometry.topLeft()); @@ -1417,19 +1417,17 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream, case QToolBarAreaLayout::ToolBarStateMarker: case QToolBarAreaLayout::ToolBarStateMarkerEx: { - QList toolBars = findChildrenHelper(mainWindow); - if (!toolBarAreaLayout.restoreState(stream, toolBars, marker)) + const auto toolBars = mainWindow->findChildren(); + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, QInternal::Live)) return false; - for (int i = 0; i < toolBars.size(); ++i) { - QToolBar *w = toolBars.at(i); - QList path = toolBarAreaLayout.indexOf(w); + for (auto *bar : toolBars) { + const QList path = toolBarAreaLayout.indexOf(bar); if (path.isEmpty()) { - QList oldPath = oldState.toolBarAreaLayout.indexOf(w); - if (oldPath.isEmpty()) { + const QList oldPath = oldState.toolBarAreaLayout.indexOf(bar); + if (oldPath.isEmpty()) continue; - } - toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(nullptr, w); + toolBarAreaLayout.docks[oldPath.at(0)].insertToolBar(nullptr, bar); } } } @@ -1757,6 +1755,23 @@ bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget) return true; } +#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) +static QTabBar::Shape tabwidgetPositionToTabBarShape(QDockWidget *w) +{ + switch (static_cast(qt_widget_private(w))->tabPosition) { + case QTabWidget::North: + return QTabBar::RoundedNorth; + case QTabWidget::South: + return QTabBar::RoundedSouth; + case QTabWidget::West: + return QTabBar::RoundedWest; + case QTabWidget::East: + return QTabBar::RoundedEast; + } + Q_UNREACHABLE_RETURN(QTabBar::RoundedSouth); +} +#endif // QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) + #if QT_CONFIG(tabbar) void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) { @@ -1821,13 +1836,13 @@ QTabWidget::TabPosition QMainWindowLayout::tabPosition(Qt::DockWidgetArea area) void QMainWindowLayout::setTabPosition(Qt::DockWidgetAreas areas, QTabWidget::TabPosition tabPosition) { - const Qt::DockWidgetArea dockWidgetAreas[] = { + static constexpr Qt::DockWidgetArea dockWidgetAreas[] = { Qt::TopDockWidgetArea, Qt::LeftDockWidgetArea, Qt::BottomDockWidgetArea, Qt::RightDockWidgetArea }; - const QInternal::DockPosition dockPositions[] = { + static constexpr QInternal::DockPosition dockPositions[] = { QInternal::TopDock, QInternal::LeftDock, QInternal::BottomDock, @@ -1856,14 +1871,14 @@ void QMainWindowLayout::showTabBars() void QMainWindowLayout::updateTabBarShapes() { #if QT_CONFIG(tabwidget) - const QTabWidget::TabPosition vertical[] = { + static constexpr QTabWidget::TabPosition vertical[] = { QTabWidget::West, QTabWidget::East, QTabWidget::North, QTabWidget::South }; #else - const QTabBar::Shape vertical[] = { + static constexpr QTabBar::Shape vertical[] = { QTabBar::RoundedWest, QTabBar::RoundedEast, QTabBar::RoundedNorth, @@ -2440,7 +2455,7 @@ void QMainWindowLayout::setCurrentHoveredFloat(QDockWidgetGroupWindow *w) if (currentHoveredFloat) currentHoveredFloat->restore(); } else if (w) { - restore(true); + restore(QInternal::KeepSavedState); } currentHoveredFloat = w; @@ -2703,14 +2718,14 @@ void QMainWindowLayout::animationFinished(QWidget *widget) updateGapIndicator(); } -void QMainWindowLayout::restore(bool keepSavedState) +void QMainWindowLayout::restore(QInternal::SaveStateRule rule) { if (!savedState.isValid()) return; layoutState = savedState; applyState(layoutState); - if (!keepSavedState) + if (rule == QInternal::ClearSavedState) savedState.clear(); currentGapPos.clear(); pluggingWidget = nullptr; @@ -2839,30 +2854,6 @@ static bool unplugGroup(QMainWindowLayout *layout, QLayoutItem **item, } #endif -#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) -static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w) -{ - QTabBar::Shape result = QTabBar::RoundedSouth; - if (qobject_cast(w)) { - switch (static_cast(qt_widget_private(w))->tabPosition) { - case QTabWidget::North: - result = QTabBar::RoundedNorth; - break; - case QTabWidget::South: - result = QTabBar::RoundedSouth; - break; - case QTabWidget::West: - result = QTabBar::RoundedWest; - break; - case QTabWidget::East: - result = QTabBar::RoundedEast; - break; - } - } - return result; -} -#endif // QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget) - /*! \internal Unplug \a widget (QDockWidget or QToolBar) from it's parent container. @@ -3128,6 +3119,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget, auto *groupWindow = qobject_cast(w); Q_ASSERT(groupWindow); if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) { + savedState.clear(); setCurrentHoveredFloat(groupWindow); applyState(layoutState); // update the tabbars } @@ -3172,7 +3164,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget, currentGapPos = path; if (path.isEmpty()) { fixToolBarOrientation(hoverTarget, 2); // 2 = top dock, ie. horizontal - restore(true); + restore(QInternal::KeepSavedState); return; } @@ -3181,7 +3173,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget, QMainWindowLayoutState newState = savedState; if (!newState.insertGap(path, hoverTarget)) { - restore(true); // not enough space + restore(QInternal::KeepSavedState); // not enough space return; } @@ -3189,7 +3181,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget, QSize size = newState.rect.size(); if (min.width() > size.width() || min.height() > size.height()) { - restore(true); + restore(QInternal::KeepSavedState); return; } diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout_p.h index fba7a5f14f..bc85f03ad9 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmainwindowlayout_p.h @@ -622,7 +622,7 @@ public: void revert(QLayoutItem *widgetItem); void applyState(QMainWindowLayoutState &newState, bool animate = true); void applyRestoredState(); - void restore(bool keepSavedState = false); + void restore(QInternal::SaveStateRule rule); void animationFinished(QWidget *widget); #if QT_CONFIG(draganddrop) diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu.cpp index 04eae43d1f..bdaab8bcfc 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu.cpp @@ -1354,7 +1354,7 @@ bool QMenuPrivate::mouseEventTaken(QMouseEvent *e) if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) tearRect.translate(0, scrollerHeight()); q->update(tearRect); - if (tearRect.contains(pos) && hasMouseMoved(e->globalPosition().toPoint())) { + if (tearRect.contains(pos) && hasMouseMoved(e->globalPosition())) { setCurrentAction(nullptr); tearoffHighlighted = 1; if (e->type() == QEvent::MouseButtonRelease) { @@ -1576,7 +1576,7 @@ void QMenuPrivate::_q_platformMenuAboutToShow() #endif } -bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos) +bool QMenuPrivate::hasMouseMoved(const QPointF &globalPos) const { //determines if the mouse has moved (ie its initial position has //changed by more than QApplication::startDragDistance() @@ -2921,7 +2921,7 @@ void QMenu::mousePressEvent(QMouseEvent *e) // Only when mouse clicks in QPoint(0,0) on second screen, the menu doesn't hide. if ((e->position().toPoint().isNull() && !e->globalPosition().isNull()) || !rect().contains(e->position().toPoint()) - || !d->hasMouseMoved(e->globalPosition().toPoint())) { + || !d->hasMouseMoved(e->globalPosition())) { if (d->noReplayFor && QRect(d->noReplayFor->mapToGlobal(QPoint()), d->noReplayFor->size()).contains(e->globalPosition().toPoint())) setAttribute(Qt::WA_NoMouseReplay); @@ -2965,7 +2965,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e) d->setSyncAction(); - if (sawMousePress && !d->hasMouseMoved(e->globalPosition().toPoint())) { + if (sawMousePress && !d->hasMouseMoved(e->globalPosition())) { // We don't want to trigger a menu item if the mouse hasn't moved // since the popup was opened. Instead we want to close the menu. d->hideUpToMenuBar(); @@ -3081,10 +3081,10 @@ bool QMenu::event(QEvent *e) case QEvent::ToolTip: if (d->toolTipsVisible) { const QHelpEvent *ev = static_cast(e); - if (const QAction *action = actionAt(ev->pos())) { + if (QAction *action = actionAt(ev->pos())) { const QString toolTip = action->d_func()->tooltip; if (!toolTip.isEmpty()) - QToolTip::showText(ev->globalPos(), toolTip, this); + QToolTip::showText(ev->globalPos(), toolTip, this, actionGeometry(action)); else QToolTip::hideText(); return true; @@ -3488,7 +3488,7 @@ void QMenu::mouseMoveEvent(QMouseEvent *e) return; d->motions++; - if (!d->hasMouseMoved(e->globalPosition().toPoint())) + if (!d->hasMouseMoved(e->globalPosition())) return; d->hasHadMouse = d->hasHadMouse || rect().contains(e->position().toPoint()); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu_p.h index d9dcd7d036..af5d5475cf 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qmenu_p.h @@ -444,7 +444,7 @@ public: void _q_actionHovered(); void _q_platformMenuAboutToShow(); - bool hasMouseMoved(const QPoint &globalPos); + bool hasMouseMoved(const QPointF &globalPos) const; void updateLayoutDirection(); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qpushbutton.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qpushbutton.cpp index 4317e11aae..480d02060a 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qpushbutton.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qpushbutton.cpp @@ -77,6 +77,8 @@ QT_BEGIN_NAMESPACE provide less commonly used signals, for example pressed() and released(). + \snippet code/src_gui_widgets_qpushbutton.cpp clicked + Command buttons in dialogs are by default auto-default buttons, i.e., they become the default push button automatically when they receive the keyboard input focus. A default button is a push diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qspinbox.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qspinbox.cpp index 6691aa37b5..2874be8189 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qspinbox.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qspinbox.cpp @@ -5,10 +5,9 @@ #include #include -#include #include +#include #include -#include #include #include @@ -18,12 +17,8 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -//#define QSPINBOX_QSBDEBUG -#ifdef QSPINBOX_QSBDEBUG -# define QSBDEBUG qDebug -#else -# define QSBDEBUG if (false) qDebug -#endif +Q_STATIC_LOGGING_CATEGORY(lcWidgetSpinBox, "qt.widgets.qspinbox") +Q_STATIC_LOGGING_CATEGORY(lcWidgetDblSpinBox, "qt.widgets.qdoublespinbox") class QSpinBoxPrivate : public QAbstractSpinBoxPrivate { @@ -59,6 +54,10 @@ public: virtual QString textFromValue(const QVariant &n) const override; QVariant validateAndInterpret(QString &input, int &pos, QValidator::State &state) const; + QVariant roundValue(const QVariant &val) const override + { + return round(val.toDouble()); + } double round(double input) const; // variables int decimals; @@ -1081,8 +1080,8 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, { if (cachedText == input && !input.isEmpty()) { state = cachedState; - QSBDEBUG() << "cachedText was '" << cachedText << "' state was " - << state << " and value was " << cachedValue; + qCDebug(lcWidgetSpinBox) << "cachedText was '" << cachedText << "' state was" << state + << "and value was" << cachedValue; return cachedValue; } @@ -1090,7 +1089,7 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, const int min = minimum.toInt(); QString copy = stripped(input, &pos); - QSBDEBUG() << "input" << input << "copy" << copy; + qCDebug(lcWidgetSpinBox) << "input" << input << "copy" << copy; state = QValidator::Acceptable; int num = min; @@ -1098,7 +1097,7 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, || (min < 0 && copy == "-"_L1) || (max >= 0 && copy == "+"_L1))) { state = QValidator::Intermediate; - QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; + qCDebug(lcWidgetSpinBox) << "num is set to" << num; } else if (copy.startsWith(u'-') && min >= 0) { state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100 } else { @@ -1117,7 +1116,7 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, } } } - QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num; + qCDebug(lcWidgetSpinBox) << "num is set to" << num; if (!ok) { state = QValidator::Invalid; } else if (num >= min && num <= max) { @@ -1125,14 +1124,12 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, } else if (max == min) { state = QValidator::Invalid; } else { - if ((num >= 0 && num > max) || (num < 0 && num < min)) { + if ((num >= 0 && num > max) || (num < 0 && num < min)) state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; - } else { + else state = QValidator::Intermediate; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; - } } + qCDebug(lcWidgetSpinBox) << "state is set to" << state; } if (state != QValidator::Acceptable) num = max > 0 ? min : max; @@ -1141,8 +1138,8 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, cachedState = state; cachedValue = QVariant((int)num); - QSBDEBUG() << "cachedText is set to '" << cachedText << "' state is set to " - << state << " and value is set to " << cachedValue; + qCDebug(lcWidgetSpinBox) << "cachedText is set to '" << cachedText << "' state is set to" + << state << "and value is set to" << cachedValue; return cachedValue; } @@ -1234,15 +1231,15 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, { if (cachedText == input && !input.isEmpty()) { state = cachedState; - QSBDEBUG() << "cachedText was '" << cachedText << "' state was " - << state << " and value was " << cachedValue; + qCDebug(lcWidgetDblSpinBox) << "cachedText was '" << cachedText << "' state was" << state + << "and value was" << cachedValue; return cachedValue; } const double max = maximum.toDouble(); const double min = minimum.toDouble(); QString copy = stripped(input, &pos); - QSBDEBUG() << "input" << input << "copy" << copy; + qCDebug(lcWidgetDblSpinBox) << "input" << input << "copy" << copy; int len = copy.size(); double num = min; const bool plus = max >= 0; @@ -1276,7 +1273,7 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, } if (groupUcs && copy.startsWith(group)) { - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; state = QValidator::Invalid; goto end; } else if (len > 1) { @@ -1287,14 +1284,14 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, } // should be treated as typing right arrow if (copy.size() - dec > decimals + 1) { - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; state = QValidator::Invalid; goto end; } for (int i = dec + 1; i < copy.size(); ++i) { if (copy.at(i).isSpace() || (groupUcs && QStringView{copy}.sliced(i).startsWith(group))) { - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; state = QValidator::Invalid; goto end; } @@ -1307,11 +1304,11 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, if ((groupEnd || last.isSpace()) && ((groupUcs && head.endsWith(group)) || secondLast.isSpace())) { state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; goto end; } else if (last.isSpace() && (!QChar::isSpace(groupUcs) || secondLast.isSpace())) { state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; goto end; } } @@ -1320,13 +1317,13 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, { bool ok = false; num = locale.toDouble(copy, &ok); - QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok; + qCDebug(lcWidgetDblSpinBox) << locale << copy << num << ok; if (!ok) { if (QChar::isPrint(groupUcs)) { if (max < 1000 && min > -1000 && groupUcs && copy.contains(group)) { state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; goto end; } @@ -1334,7 +1331,7 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, for (int i = 0; i < len - 1;) { if (groupUcs && QStringView{copy}.sliced(i).startsWith(group)) { if (QStringView(copy).mid(i + group.size()).startsWith(group)) { - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; state = QValidator::Invalid; goto end; } @@ -1348,11 +1345,11 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, if (groupUcs) copy2.remove(group); num = locale.toDouble(copy2, &ok); - QSBDEBUG() << group << num << copy2 << ok; + qCDebug(lcWidgetDblSpinBox) << group << num << copy2 << ok; if (!ok) { state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; + qCDebug(lcWidgetDblSpinBox) << "state is set to Invalid"; goto end; } } @@ -1360,22 +1357,17 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, if (!ok) { state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else if (num >= min && num <= max) { state = QValidator::Acceptable; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Acceptable"; } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min) state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { - if ((num >= 0 && num > max) || (num < 0 && num < min)) { + if ((num >= 0 && num > max) || (num < 0 && num < min)) state = QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; - } else { + else state = QValidator::Intermediate; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; - } } + qCDebug(lcWidgetDblSpinBox) << "state is set to" << state; } end: diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qsplitter.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qsplitter.cpp index d46bff98eb..7f43fad724 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qsplitter.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qsplitter.cpp @@ -258,7 +258,7 @@ void QSplitterHandle::mouseMoveEvent(QMouseEvent *e) if (!d->pressed) return; - const int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPosition().toPoint())) + const int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPosition()).toPoint()) - d->mouseOffset; if (opaqueResize()) { moveSplitter(pos); @@ -290,7 +290,7 @@ void QSplitterHandle::mouseReleaseEvent(QMouseEvent *e) return; if (!opaqueResize()) { - const int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPosition().toPoint())) + const int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPosition()).toPoint()) - d->mouseOffset; d->s->setRubberBand(-1); moveSplitter(pos); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtabbar.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtabbar.cpp index 77ae941aec..8eff0d2f02 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtabbar.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtabbar.cpp @@ -748,7 +748,7 @@ void QTabBarPrivate::layoutTab(int index) if (tab->leftWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabLeftButton, &opt, q); QPoint p = rect.topLeft(); - if (index == pressedIndex) { + if (tab->dragOffset != 0) { if (vertical) p.setY(p.y() + tab->dragOffset); else @@ -759,7 +759,7 @@ void QTabBarPrivate::layoutTab(int index) if (tab->rightWidget) { QRect rect = q->style()->subElementRect(QStyle::SE_TabBarTabRightButton, &opt, q); QPoint p = rect.topLeft(); - if (index == pressedIndex) { + if (tab->dragOffset != 0) { if (vertical) p.setY(p.y() + tab->dragOffset); else diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextbrowser.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextbrowser.cpp index 3f5ab35d46..557f8c18f2 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextbrowser.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextbrowser.cpp @@ -49,7 +49,7 @@ public: {} ~QTextBrowserPrivate() { - for (const QMetaObject::Connection &connection : connections) + for (QMetaObject::Connection &connection : connections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextedit.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextedit.cpp index 122cecdbcf..81cdac61e1 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextedit.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtextedit.cpp @@ -99,7 +99,7 @@ QTextEditPrivate::QTextEditPrivate() QTextEditPrivate::~QTextEditPrivate() { - for (const QMetaObject::Connection &connection : connections) + for (QMetaObject::Connection &connection : connections) QObject::disconnect(connection); } diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbar.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbar.cpp index 1ead2c2836..aca1bb2102 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbar.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbar.cpp @@ -211,7 +211,7 @@ void QToolBarPrivate::endDrag() if (!layout->plug(state->widgetItem)) { if (q->isFloatable()) { - layout->restore(); + layout->restore(QInternal::KeepSavedState); setWindowState(true); // gets rid of the X11BypassWindowManager window flag // and activates the resizer q->activateWindow(); diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout.cpp index 8deb6c0ec5..6f3d70b2c7 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout.cpp @@ -1272,8 +1272,9 @@ static inline int getInt(QDataStream &stream) } -bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList &_toolBars, uchar tmarker, bool testing) +bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList &_toolBars, uchar tmarker, QInternal::CallMode callMode) { + const bool testing = callMode == QInternal::Testing; QList toolBars = _toolBars; int lines; stream >> lines; diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout_p.h index 8263a592b7..672b67a894 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qtoolbararealayout_p.h @@ -179,7 +179,7 @@ public: QLayoutItem *unplug(const QList &path, QToolBarAreaLayout *other); void saveState(QDataStream &stream) const; - bool restoreState(QDataStream &stream, const QList &toolBars, uchar tmarker, bool testing = false); + bool restoreState(QDataStream &stream, const QList &toolBars, uchar tmarker, QInternal::CallMode callMode); bool isEmpty() const; }; diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol.cpp b/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol.cpp index ad279bb6ad..a1eb8d3f34 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1039,6 +1039,12 @@ void QWidgetTextControl::processEvent(QEvent *e, const QTransform &transform, QW d->mousePressEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(), ev->buttons(), ev->globalPosition()); break; } + case QEvent::Enter: + d->updateHighlightedAnchor(transform.map(static_cast(e)->position())); + break; + case QEvent::Leave: + d->resetHighlightedAnchor(); + break; case QEvent::MouseMove: { QMouseEvent *ev = static_cast(e); d->mouseMoveEvent(ev, ev->button(), transform.map(ev->position()), ev->modifiers(), @@ -1679,13 +1685,8 @@ void QWidgetTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button { Q_Q(QWidgetTextControl); - if (interactionFlags & Qt::LinksAccessibleByMouse) { - QString anchor = q->anchorAt(mousePos); - if (anchor != highlightedAnchor) { - highlightedAnchor = anchor; - emit q->linkHovered(anchor); - } - } + if (interactionFlags & Qt::LinksAccessibleByMouse) + updateHighlightedAnchor(mousePos); if (buttons & Qt::LeftButton) { const bool editable = interactionFlags & Qt::TextEditable; @@ -2979,6 +2980,25 @@ void QWidgetTextControlPrivate::activateLinkUnderCursor(QString href) emit q_func()->linkActivated(href); } +void QWidgetTextControlPrivate::updateHighlightedAnchor(QPointF mousePos) +{ + Q_Q(QWidgetTextControl); + const QString anchor = q->anchorAt(mousePos); + if (anchor != highlightedAnchor) { + highlightedAnchor = anchor; + emit q->linkHovered(anchor); + } +} + +void QWidgetTextControlPrivate::resetHighlightedAnchor() +{ + Q_Q(QWidgetTextControl); + if (!highlightedAnchor.isEmpty()) { + highlightedAnchor.clear(); + emit q->linkHovered(QString()); + } +} + #if QT_CONFIG(tooltip) void QWidgetTextControlPrivate::showToolTip(const QPoint &globalPos, const QPointF &pos, QWidget *contextWidget) { diff --git a/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol_p_p.h b/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol_p_p.h index 0f31c0b538..992c89dd72 100644 --- a/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol_p_p.h +++ b/local/recipes/qt/qtbase/source/src/widgets/widgets/qwidgettextcontrol_p_p.h @@ -100,6 +100,8 @@ public: { return selectionRect(this->cursor); } QString anchorForCursor(const QTextCursor &anchor) const; + void updateHighlightedAnchor(QPointF mousePos); + void resetHighlightedAnchor(); void keyPressEvent(QKeyEvent *e); void mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, diff --git a/local/recipes/qt/qtbase/source/src/xml/doc/qtxml.qdocconf b/local/recipes/qt/qtbase/source/src/xml/doc/qtxml.qdocconf index b778471298..e7afa7d651 100644 --- a/local/recipes/qt/qtbase/source/src/xml/doc/qtxml.qdocconf +++ b/local/recipes/qt/qtbase/source/src/xml/doc/qtxml.qdocconf @@ -50,4 +50,5 @@ navigation.toctitles.inclusive = false manifestmeta.thumbnail.names = "QtXml/XML Stream Lint Example" # Enforce zero documentation warnings +reportmissingalttextforimages = true warninglimit = 0 diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/CMakeLists.txt index aac9b43bac..2b84853776 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/CMakeLists.txt @@ -23,6 +23,10 @@ if(APPLE AND TARGET Qt::Gui) qt_internal_add_RunCMake_test(AppleFrameworkDeduplication) endif() +if(APPLE) + qt_internal_add_RunCMake_test(ApplePlistI18n) +endif() + if(TARGET Qt6::Platform) get_target_property(sbom_spdx_id Qt6::Platform _qt_sbom_spdx_id) # If the id is present and non-empty, that means we built Qt with sbom support. diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/RunCMakeTest.cmake b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/RunCMakeTest.cmake index 65f3bf3d0f..60f3bfa8a6 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/RunCMakeTest.cmake +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/RunCMakeTest.cmake @@ -1,7 +1,18 @@ +# To avoid CMP0057 if(IN_LIST) warnings +cmake_minimum_required(VERSION 3.16) + include(QtRunCMake) function(run_cmake_and_build case format_case) + set(opt_args "") + set(single_args "") + set(multi_args + SEARCH_CASE_PACKAGES + ) + cmake_parse_arguments(PARSE_ARGV 2 arg "${opt_args}" "${single_args}" "${multi_args}") + set(include_file "${case}") + set(original_case "${case}") set(case "${format_case}-${case}") # Set common build directory for configure and build @@ -13,28 +24,15 @@ function(run_cmake_and_build case format_case) "-DFORMAT_CASE=${format_case}" ) - if(format_case STREQUAL "spdx23") - list(APPEND options - -DQT_GENERATE_SBOM=ON - -DQT_SBOM_GENERATE_SPDX_V2=ON - -DQT_SBOM_GENERATE_CYDX_V1_6=OFF - ) - elseif(format_case STREQUAL "cydx16") - list(APPEND options - -DQT_GENERATE_SBOM=ON - -DQT_SBOM_GENERATE_SPDX_V2=OFF - -DQT_SBOM_GENERATE_CYDX_V1_6=ON - ) - elseif(format_case STREQUAL "all") - list(APPEND options - -DQT_GENERATE_SBOM=ON - -DQT_SBOM_GENERATE_SPDX_V2=ON - -DQT_SBOM_GENERATE_CYDX_V1_6=ON - ) - elseif(format_case STREQUAL "none") - list(APPEND options - -DQT_GENERATE_SBOM=OFF - ) + set(extra_install_prefixes "") + foreach(search_case IN LISTS arg_SEARCH_CASE_PACKAGES) + set(case_install_prefix + "${RunCMake_BINARY_DIR}/${format_case}-${search_case}-build/installed") + list(APPEND extra_install_prefixes "${case_install_prefix}") + endforeach() + + if (extra_install_prefixes) + list(APPEND options "-DCMAKE_PREFIX_PATH=${extra_install_prefixes}") endif() # Check CI environment variables for SBOM options to ensure we only enabled checks that @@ -58,9 +56,100 @@ function(run_cmake_and_build case format_case) list(APPEND options "-DQT_INTERNAL_SBOM_AUDIT_NO_ERROR=ON") endif() - if(maybe_sbom_env_args MATCHES "QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON" - OR force_all_checks) - list(APPEND options "-DQT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON") + set(require_spdx_json FALSE) + if(maybe_sbom_env_args MATCHES "QT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON=ON" OR force_all_checks) + set(require_spdx_json TRUE) + endif() + + set(require_cydx FALSE) + if(maybe_sbom_env_args MATCHES "QT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON" OR force_all_checks) + set(require_cydx TRUE) + endif() + + if(format_case STREQUAL "spdx23") + list(APPEND options + -DQT_GENERATE_SBOM=ON + -DEXPECTED_QT_GENERATE_SBOM=ON + + # Don't explicitly enable QT_SBOM_GENERATE_SPDX_V2 and QT_SBOM_GENERATE_SPDX_V2_JSON, + # The are implicitly ON. + # Make sure the tag value format is always generated. + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2=ON + + # Explicitly disable CYDX though. + -DQT_SBOM_GENERATE_CYDX_V1_6=OFF + -DEXPECTED_QT_SBOM_GENERATE_CYDX_V1_6=OFF + ) + if(require_spdx_json) + # Require spdx json because because we assume we have the required dependencies from + # reading the env var. + list(APPEND options + -DQT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON=ON + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2_JSON=ON + ) + endif() + elseif(format_case STREQUAL "cydx16") + list(APPEND options + -DQT_GENERATE_SBOM=ON + + # Don't explicitly enable QT_SBOM_GENERATE_CYDX_V1_6. + # It is implicitly ON. + + # Explicitly disable SPDX though. + -DQT_SBOM_GENERATE_SPDX_V2=OFF + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2=OFF + -DQT_SBOM_GENERATE_SPDX_V2_JSON=OFF + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2_JSON=OFF + ) + if(require_cydx) + list(APPEND options + # This case is different from the others because if cydx deps are not found, + # we will end up disabling both CYDX and GENERATE_SBOM, so we can only expect + # this to be ON when we require cydx and the deps are found. + # The assymetry is not very intuitive, but changing the behavior is too late. + -DEXPECTED_QT_GENERATE_SBOM=ON + + # Require cydx because because we assume we have the required dependencies from + # reading the env var. + -DQT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON + -DEXPECTED_QT_SBOM_GENERATE_CYDX_V1_6=ON + ) + endif() + elseif(format_case STREQUAL "all") + list(APPEND options + -DQT_GENERATE_SBOM=ON + -DEXPECTED_QT_GENERATE_SBOM=ON + + # Don't explicitly enable neither spdx nor cydx, they are both implicitly ON. + # Make sure the tag value format is always generated. + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2=ON + ) + if(require_spdx_json) + # Require spdx json because because we assume we have the required dependencies from + # reading the env var. + list(APPEND options + -DQT_SBOM_REQUIRE_GENERATE_SPDX_V2_JSON=ON + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2_JSON=ON + ) + endif() + if(require_cydx) + # Require cydx because because we assume we have the required dependencies from + # reading the env var. + list(APPEND options + -DQT_SBOM_REQUIRE_GENERATE_CYDX_V1_6=ON + -DEXPECTED_QT_SBOM_GENERATE_CYDX_V1_6=ON + ) + endif() + elseif(format_case STREQUAL "none") + list(APPEND options + -DQT_GENERATE_SBOM=OFF + -DEXPECTED_QT_GENERATE_SBOM=OFF + + # Confirm that the other values are implicitly ON, even though they won't be + # generated. + -DEXPECTED_QT_SBOM_GENERATE_SPDX_V2_JSON=ON + -DEXPECTED_QT_SBOM_GENERATE_CYDX_V1_6=ON + ) endif() # Need to pass the python interpreter paths, to avoid sbom2doc not found errors. @@ -84,8 +173,16 @@ function(run_cmake_and_build case format_case) set(RunCMake_TEST_OUTPUT_MERGE 1) run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .) - # Check the sbom files are present after installation. - set(RunCMake-check-file "check.cmake") + # Check the sbom files are present after installation. Use generic check.cmake, unless there's + # a case-specific one. + set(rel_case_specific_check "${original_case}-install-check.cmake") + set(abs_case_specific_check "${CMAKE_CURRENT_LIST_DIR}/${rel_case_specific_check}") + if(EXISTS "${abs_case_specific_check}") + set(RunCMake-check-file "${rel_case_specific_check}") + else() + set(RunCMake-check-file "check.cmake") + endif() + run_cmake_command(${case}-install ${CMAKE_COMMAND} --install .) unset(RunCMake-check-file) endfunction() @@ -95,5 +192,19 @@ foreach(format_case IN LISTS format_cases) run_cmake_and_build(minimal "${format_case}") run_cmake_and_build(full "${format_case}") run_cmake_and_build(versions "${format_case}") + run_cmake_and_build(target_relationships "${format_case}") + + # The next test depends on the previous one successfully passing. + run_cmake_and_build(target_relationships_external "${format_case}" + SEARCH_CASE_PACKAGES target_relationships) + + run_cmake_and_build(project_relationships "${format_case}") + run_cmake_and_build(spdx_suffixes "${format_case}") + + # The next test depends on the previous one successfully passing. + run_cmake_and_build(spdx_suffixes_external "${format_case}" + SEARCH_CASE_PACKAGES spdx_suffixes) + + run_cmake_and_build(build_tools "${format_case}") endforeach() diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/check.cmake b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/check.cmake index 9e143e35ab..b0ec5351b2 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/check.cmake +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/check.cmake @@ -18,26 +18,212 @@ function(check_not_exists file) set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) endfunction() +# Asserts that the given needle string exists in the SPDX v2.3 document. +function(assert_str_exists_in_spdx_v2_3_doc needle) + if(NOT SPDX_V2_3_DOCUMENTS) + return() + endif() + list(GET SPDX_V2_3_DOCUMENTS 0 doc_name) + file(READ "${doc_name}" doc_contents) + if(NOT doc_contents MATCHES "${needle}") + string(APPEND RunCMake_TEST_FAILED + "Expected to find '${needle}' in SPDX v2.3 document '${doc_name}'," + " but it was not found.\n\n doc contents \n${doc_contents}}.\n") + endif() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +# Asserts that all needles in SPDX_V2_3_STR_ASSERT_NEEDLES exist in the SPDX v2.3 document. +function(check_assert_str_exists_in_spdx_v2_3_doc_needles) + foreach(needle IN LISTS SPDX_V2_3_STR_ASSERT_NEEDLES) + assert_str_exists_in_spdx_v2_3_doc("${needle}") + endforeach() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +# Asserts that the given needle string exists in the CycloneDX v1.6 document. +# Currently unused. +function(assert_str_exists_in_cydx_v1_6_doc needle) + if(NOT CYDX_V1_6_DOCUMENTS) + return() + endif() + + list(GET CYDX_V1_6_DOCUMENTS 0 doc_name) + file(READ "${doc_name}" doc_contents) + if(NOT doc_contents MATCHES "${needle}") + string(APPEND RunCMake_TEST_FAILED + "Expected to find '${needle}' in CyDX v1.6 document '${doc_name}'," + " but it was not found.\n") + endif() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +# Asserts that all needles in CYDX_V1_6_STR_ASSERT_NEEDLES exist in the CycloneDX v1.6 document. +# Currently unused. +function(check_assert_str_exists_in_cydx_v1_6_doc_needles) + foreach(needle IN LISTS CYDX_V1_6_STR_ASSERT_NEEDLES) + assert_str_exists_in_cydx_v1_6_doc("${needle}") + endforeach() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +# Gets the first CycloneDX v1.6 document path from the parent scope. +function(get_cydx_v1_6_doc_path out_var) + if(NOT CYDX_V1_6_DOCUMENTS) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + list(GET CYDX_V1_6_DOCUMENTS 0 doc_path) + set(${out_var} "${doc_path}" PARENT_SCOPE) +endfunction() + +# Gets the contents of the first CycloneDX v1.6 document from the parent scope. +function(get_cydx_v1_6_doc_contents out_var) + if(NOT CYDX_V1_6_DOCUMENTS) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + list(GET CYDX_V1_6_DOCUMENTS 0 doc_name) + + if(NOT EXISTS "${doc_name}") + string(APPEND RunCMake_TEST_FAILED "CycloneDX document '${doc_name}' does not exist.\n") + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + set(${out_var} "" PARENT_SCOPE) + return() + endif() + + file(READ "${doc_name}" doc_contents) + set(${out_var} "${doc_contents}" PARENT_SCOPE) +endfunction() + +# Verifies that the given targets have their dependencies correctly represented in +# the CycloneDX v1.6 document. +# The expected dependencies for each target must be set in the parent scope using +# add_extra_code_to_result_file. +function(check_cydx_v1_6_dependencies) + set(opt_args "") + set(single_args + TARGETS_CATEGORY + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 0 arg "${opt_args}" "${single_args}" "${multi_args}") + + # Var is set in parent scope. + if(NOT CYDX_V1_6_DOCUMENTS) + return() + endif() + + if(NOT arg_TARGETS_CATEGORY) + string(APPEND RunCMake_TEST_FAILED + "Expected argument 'TARGETS_CATEGORY' to be passed.\n") + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + return() + endif() + + # Taken from parent scope. + get_cydx_v1_6_doc_contents(cydx_contents) + if(NOT cydx_contents) + string(APPEND RunCMake_TEST_FAILED + "Failed to get contents of CycloneDX document for dependency checks.\n") + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + return() + endif() + get_cydx_v1_6_doc_path(cydx_path) + + string(JSON dependencies GET "${cydx_contents}" "dependencies") + string(JSON dependencies_length LENGTH "${dependencies}") + + # Collect component spdx ids from the dependencies key of the cdx document. + set(doc_spdx_ids "") + + set(idx 0) + while(idx LESS dependencies_length) + string(JSON dependency GET "${dependencies}" "${idx}") + + string(JSON ref GET "${dependency}" "ref") + list(APPEND doc_spdx_ids "${ref}") + + string(JSON depends_on_length ERROR_VARIABLE depends_on_error LENGTH "${dependency}" "dependsOn") + if(depends_on_error STREQUAL "NOTFOUND") + set(dep_idx 0) + while(dep_idx LESS depends_on_length) + string(JSON depends_on_item GET "${dependency}" "dependsOn" "${dep_idx}") + math(EXPR dep_idx "${dep_idx} + 1") + + # Collect the deps of each component spdx id. + list(APPEND doc_spdx_ids_${ref}_deps "${depends_on_item}") + endwhile() + endif() + + math(EXPR idx "${idx} + 1") + endwhile() + + # Sort deps, so that equality checks of lists work. + foreach(spdx_id IN LISTS doc_spdx_ids) + list(SORT doc_spdx_ids_${spdx_id}_deps) + endforeach() + + # Check that the targets category var is defined in the parent scope, even if it's empty. + set(targets_var "KNOWN_TARGETS_${arg_TARGETS_CATEGORY}") + if(NOT DEFINED "${targets_var}") + string(APPEND RunCMake_TEST_FAILED + "Expected variable '${targets_var}' to be defined in 'result.cmake' file.\n") + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) + return() + endif() + + # Go through the recorded targets, and confirm that the spdx ids and dependencies specified + # in the parent scope match those in the CycloneDX document. + set(targets "${${targets_var}}") + foreach(target IN LISTS targets) + # This var is set in the parent scope. + set(target_spdx_id "${${target}_SPDX_ID}") + + if(NOT "${target_spdx_id}" IN_LIST doc_spdx_ids) + string(APPEND RunCMake_TEST_FAILED + "Component ID '${target_spdx_id}' not found in CycloneDX document" + " '${cydx_path}'.\n") + endif() + # This var is set in parent scope. + set(expected_target_deps "${${target}_DEPS}") + + set(current_docs_target_deps "${doc_spdx_ids_${target_spdx_id}_deps}") + if(NOT expected_target_deps STREQUAL current_docs_target_deps) + string(APPEND RunCMake_TEST_FAILED + "Component ID '${target_spdx_id}' dependencies do not match expected " + "dependencies.\n" + " Expected: '${expected_target_deps}'\n" + " Found: '${current_docs_target_deps}'\n") + endif() + endforeach() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + # Check that the correct option values are used for the project root sbom. set(root_result_file "${RunCMake_TEST_BINARY_DIR}/result.cmake") if(EXISTS "${root_result_file}") include("${root_result_file}") - if(NOT "${ORIGINAL_QT_GENERATE_SBOM}" STREQUAL "${RESULT_QT_GENERATE_SBOM}") + if(NOT EXPECTED_QT_GENERATE_SBOM STREQUAL "" AND + NOT "${EXPECTED_QT_GENERATE_SBOM}" STREQUAL "${RESULT_QT_GENERATE_SBOM}") string(APPEND RunCMake_TEST_FAILED - "QT_GENERATE_SBOM is ${RESULT_QT_GENERATE_SBOM}, expected ${ORIGINAL_QT_GENERATE_SBOM} \n") + "QT_GENERATE_SBOM is ${RESULT_QT_GENERATE_SBOM}, expected ${EXPECTED_QT_GENERATE_SBOM} \n") endif() - if(NOT "${ORIGINAL_QT_SBOM_GENERATE_SPDX_V2}" STREQUAL "${RESULT_QT_SBOM_GENERATE_SPDX_V2}") + if(NOT EXPECTED_QT_SBOM_GENERATE_SPDX_V2 STREQUAL "" AND + NOT "${EXPECTED_QT_SBOM_GENERATE_SPDX_V2}" STREQUAL "${RESULT_QT_SBOM_GENERATE_SPDX_V2}") string(APPEND RunCMake_TEST_FAILED "QT_SBOM_GENERATE_SPDX_V2 is ${RESULT_QT_SBOM_GENERATE_SPDX_V2}, " - "expected ${ORIGINAL_QT_SBOM_GENERATE_SPDX_V2} \n") + "expected ${EXPECTED_QT_SBOM_GENERATE_SPDX_V2} \n") endif() - if(NOT "${ORIGINAL_QT_SBOM_GENERATE_CYDX_V1_6}" STREQUAL "${RESULT_QT_SBOM_GENERATE_CYDX_V1_6}") + if(NOT EXPECTED_QT_SBOM_GENERATE_CYDX_V1_6 STREQUAL "" AND + NOT "${EXPECTED_QT_SBOM_GENERATE_CYDX_V1_6}" STREQUAL "${RESULT_QT_SBOM_GENERATE_CYDX_V1_6}") string(APPEND RunCMake_TEST_FAILED "QT_SBOM_GENERATE_CYDX_V1_6 is ${RESULT_QT_SBOM_GENERATE_CYDX_V1_6}, " - "expected ${ORIGINAL_QT_SBOM_GENERATE_CYDX_V1_6} \n") + "expected ${EXPECTED_QT_SBOM_GENERATE_CYDX_V1_6} \n") endif() endif() @@ -61,3 +247,5 @@ foreach(result_file IN LISTS result_files) endforeach() endforeach() +check_assert_str_exists_in_spdx_v2_3_doc_needles() +check_assert_str_exists_in_cydx_v1_6_doc_needles() diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGen.cmake b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGen.cmake index a892fee208..342dd5ffcb 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGen.cmake +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGen.cmake @@ -22,10 +22,13 @@ set(cydx_file "${sbom_install_dir}/${sbom_document_base_name}.cdx.json") set(sbom_documents "") set(no_sbom_documents "") +set(spdx_v2_3_documents "") +set(cydx_v1_6_documents "") if(FORMAT_CASE STREQUAL "spdx23" OR FORMAT_CASE STREQUAL "all") if(QT_SBOM_GENERATE_SPDX_V2) list(APPEND sbom_documents "${spdx_file}") + list(APPEND spdx_v2_3_documents "${spdx_file}") else() list(APPEND no_sbom_documents "${spdx_file}") endif() @@ -40,6 +43,7 @@ endif() if(FORMAT_CASE STREQUAL "cydx16" OR FORMAT_CASE STREQUAL "all") if(QT_SBOM_GENERATE_CYDX_V1_6) list(APPEND sbom_documents "${cydx_file}") + list(APPEND cydx_v1_6_documents "${cydx_file}") else() list(APPEND no_sbom_documents "${cydx_file}") endif() @@ -57,11 +61,16 @@ file(GENERATE " set(SBOM_DOCUMENTS \"${sbom_documents}\") set(NO_SBOM_DOCUMENTS \"${no_sbom_documents}\") -set(ORIGINAL_QT_GENERATE_SBOM \"${original_QT_GENERATE_SBOM}\") -set(ORIGINAL_QT_SBOM_GENERATE_SPDX_V2 \"${original_QT_SBOM_GENERATE_SPDX_V2}\") -set(ORIGINAL_QT_SBOM_GENERATE_CYDX_V1_6 \"${original_QT_SBOM_GENERATE_CYDX_V1_6}\") +set(SPDX_V2_3_DOCUMENTS \"${spdx_v2_3_documents}\") +set(CYDX_V1_6_DOCUMENTS \"${cydx_v1_6_documents}\") +set(EXPECTED_QT_GENERATE_SBOM \"${EXPECTED_QT_GENERATE_SBOM}\") +set(EXPECTED_QT_SBOM_GENERATE_SPDX_V2 \"${EXPECTED_QT_SBOM_GENERATE_SPDX_V2}\") +set(EXPECTED_QT_SBOM_GENERATE_CYDX_V1_6 \"${EXPECTED_QT_SBOM_GENERATE_CYDX_V1_6}\") set(RESULT_QT_GENERATE_SBOM \"${QT_GENERATE_SBOM}\") set(RESULT_QT_SBOM_GENERATE_SPDX_V2 \"${QT_SBOM_GENERATE_SPDX_V2}\") set(RESULT_QT_SBOM_GENERATE_CYDX_V1_6 \"${QT_SBOM_GENERATE_CYDX_V1_6}\") +set(SPDX_V2_3_STR_ASSERT_NEEDLES \"${SPDX_V2_3_STR_ASSERT_NEEDLES}\") +set(CYDX_V1_6_STR_ASSERT_NEEDLES \"${CYDX_V1_6_STR_ASSERT_NEEDLES}\") +${EXTRA_RESULT_CODE} " ) diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGenIntro.cmake b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGenIntro.cmake index 11ec50d76d..17e2df1b5d 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGenIntro.cmake +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/RunCMake/Sbom/cmake/CommonResultGenIntro.cmake @@ -1,12 +1,63 @@ -# Record the sbom option values before they might be modified by an sbom_setup call, due to -# missing python dependencies. -set(original_QT_GENERATE_SBOM "${QT_GENERATE_SBOM}") -set(original_QT_SBOM_GENERATE_SPDX_V2 "${QT_SBOM_GENERATE_SPDX_V2}") -set(original_QT_SBOM_GENERATE_CYDX_V1_6 "${QT_SBOM_GENERATE_CYDX_V1_6}") +# Adds a string that is expected to exist in the SPDX v2.3 document. +# This gets written to the result.cmake file, which is then checked by the check.cmake file. +function(add_assert_str_exists_in_spdx_v2_3_doc needle) + list(APPEND SPDX_V2_3_STR_ASSERT_NEEDLES "${needle}") + set(SPDX_V2_3_STR_ASSERT_NEEDLES "${SPDX_V2_3_STR_ASSERT_NEEDLES}" PARENT_SCOPE) +endfunction() -# Explicitly set these because none case only has QT_GENERATE_SBOM passed as OFF. -# In this case, the defaults for the formats is to remain ON. -if(NOT QT_GENERATE_SBOM) - set(original_QT_SBOM_GENERATE_SPDX_V2 ON) - set(original_QT_SBOM_GENERATE_CYDX_V1_6 ON) -endif() +# Adds extra code to the result.cmake file that will be generated. +function(add_extra_code_to_result_file contents) + set(new_contents "${EXTRA_RESULT_CODE} +${contents} +") + set(EXTRA_RESULT_CODE "${new_contents}" PARENT_SCOPE) +endfunction() + +# Adds the given target to the list of known targets in the result.cmake file, along with +# metadata like category and SPDX ID. Used by the check.cmake infrastructure to do checks. +function(add_known_target target) + set(opt_args "") + set(single_args + CATEGORY + SPDX_ID + ) + set(multi_args "") + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + + add_extra_code_to_result_file(" +list(APPEND KNOWN_TARGETS \"${target}\") +") + + if(arg_CATEGORY) + add_extra_code_to_result_file(" +list(APPEND KNOWN_TARGETS_${arg_CATEGORY} \"${target}\") +") + endif() + + if(arg_SPDX_ID) + add_extra_code_to_result_file(" +set(${target}_SPDX_ID \"${arg_SPDX_ID}\") +") + endif() + + bubble_up_extra_result_code() +endfunction() + +# Adds the expected dependencies for the given target to the extra result code. +function(add_cydx_v1_6_deps_to_result_file target) + set(opt_args "") + set(single_args "") + set(multi_args + DEPS + ) + cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}") + + add_extra_code_to_result_file(" +set(${target}_DEPS \"${arg_DEPS}\") +") + bubble_up_extra_result_code() +endfunction() + +macro(bubble_up_extra_result_code) + set(EXTRA_RESULT_CODE "${EXTRA_RESULT_CODE}" PARENT_SCOPE) +endmacro() diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/mockplugins/.cmake.conf b/local/recipes/qt/qtbase/source/tests/auto/cmake/mockplugins/.cmake.conf index be788d10f8..3c56bae820 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/mockplugins/.cmake.conf +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/mockplugins/.cmake.conf @@ -1 +1 @@ -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.11.1") diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf index be788d10f8..3c56bae820 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf @@ -1 +1 @@ -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.11.1") diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_qt_extract_metatypes/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_qt_extract_metatypes/CMakeLists.txt index 100e890dc8..f76371f2ae 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_qt_extract_metatypes/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_qt_extract_metatypes/CMakeLists.txt @@ -93,7 +93,9 @@ file(TIMESTAMP "${meta_types_file}" new_metatypes_timestamp) # change the resulting .json file content. set(extract_metatypes_uses_dep_files FALSE) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.17") # Requires automoc changes present only in 3.17 - if(CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + if(CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" + OR (CMAKE_VERSION VERSION_GREATER_EQUAL "4.4" + AND (CMAKE_GENERATOR STREQUAL "Xcode" OR CMAKE_GENERATOR MATCHES "^Visual Studio "))) set(extract_metatypes_uses_dep_files TRUE) endif() endif() diff --git a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_static_resources/.cmake.conf b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_static_resources/.cmake.conf index be788d10f8..3c56bae820 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/cmake/test_static_resources/.cmake.conf +++ b/local/recipes/qt/qtbase/source/tests/auto/cmake/test_static_resources/.cmake.conf @@ -1 +1 @@ -set(QT_REPO_MODULE_VERSION "6.11.0") +set(QT_REPO_MODULE_VERSION "6.11.1") diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt index 6e1ac655ba..94fcc6e4af 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/animation/qabstractanimation/CMakeLists.txt @@ -14,6 +14,8 @@ endif() qt_internal_add_test(tst_qabstractanimation SOURCES tst_qabstractanimation.cpp + DEFINES + QT_NO_CAST_FROM_BYTEARRAY LIBRARIES Qt::TestPrivate ) diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/CMakeLists.txt index 2d4afc6569..1e9ed1b32b 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/CMakeLists.txt @@ -19,7 +19,7 @@ qt_internal_add_test(tst_qfloat16 ) # To test std::format support, if possible -if(QT_FEATURE_cxx20_format) +if(QT_FEATURE_cxx20_format AND CMAKE_CXX_STANDARD VERSION_LESS 20) set_target_properties(tst_qfloat16 PROPERTIES CXX_STANDARD 20 diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp index a84477d6a2..7f0cc42f94 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp @@ -90,6 +90,46 @@ void tst_qfloat16::compareCompiles() #endif } +template static constexpr bool checkArithmeticCompiles(qfloat16 lhs, RHS rhs) +{ + auto assertIsFloat16Ref = [](auto &v) { + static_assert(std::is_same_v, qfloat16>); + }; + auto assertType = [](auto v) { + // C++23 conversion rules (q.v. P1467): + // - FP op integral -> double + // - FP op OtherFP -> the one with higher conversion rank + // all other, supported FP types have a higher rank and are a superset + using Expected = std::conditional_t, double, RHS>; + static_assert(std::is_same_v); + }; + + auto ps = +lhs; // unary + + auto ng = -lhs; // unary - + static_assert(std::is_same_v || true); // broken, uses operator NearestFloat() + static_assert(std::is_same_v); + + assertType(lhs + rhs); + assertType(lhs - rhs); + assertType(lhs * rhs); + assertType(lhs / RHS(1)); // avoid division by zero + + assertType(rhs + lhs); + assertType(rhs - lhs); + assertType(rhs * lhs); + assertType(rhs / qfloat16(1.0f)); // avoid division by zero + + // operators op=(integral) are missing + if constexpr (!std::is_integral_v) { + assertIsFloat16Ref(lhs += rhs); + assertIsFloat16Ref(lhs -= rhs); + assertIsFloat16Ref(lhs *= rhs); + assertIsFloat16Ref(lhs /= RHS(1)); // avoid division by zero + } + + return true; +} + void tst_qfloat16::relationalOperatorsAreConstexpr() { #if QFLOAT16_IS_NATIVE @@ -524,6 +564,11 @@ void tst_qfloat16::arithOps() { QFETCH(float, val1); QFETCH(float, val2); + checkArithmeticCompiles(qfloat16(val1), qfloat16(val2)); + checkArithmeticCompiles(qfloat16(val1), val2); + checkArithmeticCompiles(qfloat16(val1), val2 + 0.0); + checkArithmeticCompiles(qfloat16(val1), val2 + 0.0L); + checkArithmeticCompiles(qfloat16(val1), int(val2)); QVERIFY(qFuzzyCompare(float(qfloat16(val1) + qfloat16(val2)), val1 + val2)); QVERIFY(qFuzzyCompare(float(qfloat16(val1) - qfloat16(val2)), val1 - val2)); diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/CMakeLists.txt index 7972f1b3cb..dd1dda7e94 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/CMakeLists.txt @@ -16,6 +16,7 @@ qt_internal_add_test(tst_qglobal expansion_to_defined_check.h qglobal.c tst_qglobal.cpp + warnings.cpp NO_PCH_SOURCES tst_qglobal.cpp # undef QT_NO_FOREACH ) @@ -26,6 +27,7 @@ qt_internal_add_test(tst_qglobal_strict expansion_to_defined_check.h qglobal.c tst_qglobal.cpp + warnings.cpp DEFINES tst_QGlobal=tst_QGlobal_strict NO_PCH_SOURCES @@ -33,5 +35,12 @@ qt_internal_add_test(tst_qglobal_strict ) _qt_internal_apply_strict_cpp(tst_qglobal_strict) +# enable -Werror for just the warnings.cpp TU (applies to both targets): +if (MSVC) + set_source_files_properties(warnings.cpp PROPERTIES COMPILE_FLAGS "/WX") +else() + set_source_files_properties(warnings.cpp PROPERTIES COMPILE_FLAGS "-Werror") +endif() + ## Scopes: ##################################################################### diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index 04c77450d2..e8d631ad1c 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -91,6 +91,7 @@ class tst_QGlobal: public QObject private slots: void accessibleStateBC(); void cMode(); + void warnings() { extern void warnings_linker_hook(); warnings_linker_hook(); } void qIsNull(); void for_each(); void qassert(); diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 34c0fd11be..11fb918462 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -1045,33 +1045,33 @@ namespace SaturateCastTest { template static constexpr T max = std::numeric_limits::max(); template static constexpr T min = std::numeric_limits::min(); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == qint64(max)); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == qint64(max)); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == unsigned(max)); -static_assert(q26::saturate_cast(max) == qint64(max)); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == unsigned(max)); +static_assert(q26::saturating_cast(max) == qint64(max)); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == quint64(max)); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == quint64(max)); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); -static_assert(q26::saturate_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); +static_assert(q26::saturating_cast(max) == max); -static_assert(q26::saturate_cast(min) == min); -static_assert(q26::saturate_cast(min) == qint64(min)); -static_assert(q26::saturate_cast(min) == 0); -static_assert(q26::saturate_cast(min) == 0); +static_assert(q26::saturating_cast(min) == min); +static_assert(q26::saturating_cast(min) == qint64(min)); +static_assert(q26::saturating_cast(min) == 0); +static_assert(q26::saturating_cast(min) == 0); -static_assert(q26::saturate_cast(min) == min); -static_assert(q26::saturate_cast(min) == min); -static_assert(q26::saturate_cast(min) == 0); -static_assert(q26::saturate_cast(min) == 0); +static_assert(q26::saturating_cast(min) == min); +static_assert(q26::saturating_cast(min) == min); +static_assert(q26::saturating_cast(min) == 0); +static_assert(q26::saturating_cast(min) == 0); } // namespace SaturateCastTest diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/io/largefile/tst_largefile.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/io/largefile/tst_largefile.cpp index 526eb4c1f0..4d18d10f56 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/io/largefile/tst_largefile.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/io/largefile/tst_largefile.cpp @@ -504,6 +504,8 @@ void tst_LargeFile::mapFile() //Windows: memory-mapping beyond EOF is not allowed //wasm: as for linux //VxWorks: memory-mapping beyond EOF is not allowed +//QNX: 7.x permits mapping beyond EOF (access faults with SIGBUS); +// 8.0 rejects it with ENXIO at mmap() time void tst_LargeFile::mapOffsetOverflow() { #if defined(Q_OS_WIN) @@ -515,7 +517,7 @@ void tst_LargeFile::mapOffsetOverflow() #elif (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && (Q_PROCESSOR_WORDSIZE == 4) constexpr bool Succeeds = true; constexpr int MaxOffset = sizeof(QT_OFF_T) > 4 ? 43 : 30; -#elif defined(Q_OS_VXWORKS) +#elif defined(Q_OS_VXWORKS) || (defined(__QNX__) && __QNX__ >= 800) constexpr bool Succeeds = false; constexpr int MaxOffset = 8 * sizeof(QT_OFF_T) - 1; #else diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp index 52c3bc4217..82f1b08758 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp @@ -100,6 +100,8 @@ private slots: void treeMoveRowBranches(); void adlTest(); + + void itemAccess_data(); void itemAccess(); private: @@ -110,10 +112,12 @@ private: { QList pmiList; for (int row = 0; row < model->rowCount(parent); ++row) { - const QModelIndex mi = model->index(row, 0, parent); - pmiList += mi; - if (model->hasChildren(mi)) - pmiList += allIndexes(model, mi); + for (int column = 0; column < model->columnCount(parent); ++column) { + const QModelIndex mi = model->index(row, column, parent); + pmiList += mi; + if (model->hasChildren(mi)) + pmiList += allIndexes(model, mi); + } } return pmiList; } @@ -2263,19 +2267,46 @@ struct QRangeModel::ItemAccess } }; +void tst_QRangeModel::itemAccess_data() +{ + QTest::addColumn>("model"); + + QTest::addRow("raw") + << std::make_shared(QList{ + new ItemAccessItem{"one", Qt::red} + }); + + QTest::addRow("std::shared_ptr") + << std::make_shared(QList>{ + std::make_shared("one", Qt::red), + }); + + { + auto data = std::vector>{}; + data.emplace_back(std::make_unique("one", Qt::red)); + auto model = std::make_shared(std::move(data)); + QTest::addRow("std::unique_ptr") + << model; + } + + QTest::addRow("QSharedPtr") + << std::make_shared(QList>{ + QSharedPointer(new ItemAccessItem{"one", Qt::red}) + }); +} + void tst_QRangeModel::itemAccess() { - QRangeModel model(QList{ - new ItemAccessItem{"one", Qt::red} - }); - const QModelIndex index = model.index(0, 0); - QCOMPARE(model.columnCount(), 1); - QCOMPARE(model.data(index), "ONE"); - QCOMPARE(model.data(index, Qt::DecorationRole).value().alpha(), 128); - QVERIFY(model.setData(index, "Two")); - QCOMPARE(model.data(index), "TWO"); - QVERIFY(!model.setData(index, QVariant::fromValue(Qt::blue), Qt::DecorationRole)); -}; + QFETCH(std::shared_ptr, model); + + QCOMPARE(model->columnCount(), 1); + const QModelIndex index = model->index(0, 0); + QCOMPARE(model->data(index), "ONE"); + QCOMPARE(model->data(index, Qt::DecorationRole).value().alpha(), 128); + QVERIFY(model->setData(index, "Two")); + QCOMPARE(model->data(index), "TWO"); + QVERIFY(!model->setData(index, QVariant::fromValue(Qt::blue), Qt::DecorationRole)); +} QTEST_MAIN(tst_QRangeModel) #include "tst_qrangemodel.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp index 0f193d02ab..78cbf7e272 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp @@ -77,6 +77,7 @@ private slots: void treeIterate(); void treeAccess(); void treeWriteAccess(); + void treeFindRecursively(); void insertRow(); void insertRows(); @@ -2038,6 +2039,29 @@ void tst_QRangeModelAdapter::treeWriteAccess() } } +void tst_QRangeModelAdapter::treeFindRecursively() +{ + QRangeModelAdapter adapter(createValueTree()); + QStringView needle = u"2.3.2"; + QList path; + while (true) { + auto it = std::find_if(adapter.cbegin(), adapter.cend(), [needle](const auto &row){ + return needle.startsWith(row->value()); + }); + QVERIFY(it != adapter.cend()); + path.append(it - adapter.cbegin()); + if (it->value() == needle) + break; + if ((*it).hasChildren()) { + adapter = (*it).children(); + } else { + path = {}; + break; + } + } + QCOMPARE(path, (QList{1, 2, 1})); +} + void tst_QRangeModelAdapter::insertRow() { { diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/CMakeLists.txt index aea513cf6a..6d6960060a 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/CMakeLists.txt @@ -2,6 +2,7 @@ # SPDX-License-Identifier: BSD-3-Clause add_subdirectory(qapplicationstatic) +add_subdirectory(qapplicationstatic_static_qcoreapplication) add_subdirectory(qchronotimer) add_subdirectory(qcoreapplication) add_subdirectory(qdeadlinetimer) diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index 894f5adcdf..3a62c92ee4 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -815,6 +815,43 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() } while (t.elapsed() < 1000); } +void tst_QCoreApplication::queuedConnectionProcessEventsInSlot() +{ + // Regression test for QTBUG-142807 + + int argc = 1; + char *argv[] = { const_cast(QTest::currentAppName()) }; + TestApplication app(argc, argv); + + bool slot1Executed = false; + bool slot2Executed = false; + bool slot2DuringSlot1 = false; + + QObject signalSource; + QObject *receiver1 = new QObject(&app); + QObject *receiver2 = new QObject(&app); + + QObject::connect(&signalSource, &QObject::objectNameChanged, receiver1, [&] { + slot1Executed = true; + for (int i = 0; i < 10 && !slot2Executed; ++i) + QCoreApplication::processEvents(); + + if (slot2Executed) + slot2DuringSlot1 = true; + }, Qt::QueuedConnection); + + QObject::connect(&signalSource, &QObject::objectNameChanged, receiver2, [&] { + slot2Executed = true; + }, Qt::QueuedConnection); + + signalSource.setObjectName("trigger"); + app.processEvents(); + + QVERIFY(slot1Executed); + QVERIFY(slot2Executed); + QVERIFY(slot2DuringSlot1); +} + #ifdef Q_OS_WIN void tst_QCoreApplication::sendPostedEventsInNativeLoop() { diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h index 45dd6a1868..e18d94374b 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.h @@ -34,6 +34,7 @@ private slots: void globalPostedEventsCount(); #endif void processEventsAlwaysSendsPostedEvents(); + void queuedConnectionProcessEventsInSlot(); #ifdef Q_OS_WIN void sendPostedEventsInNativeLoop(); #endif diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 34bb6db46a..308084f370 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -1179,14 +1179,14 @@ public: enum MyEnum { A = 0x01, B = 0x02 }; Q_DECLARE_FLAGS(MyEnumFlag, MyEnum) Q_FLAG(MyEnumFlag) - Q_ENUMS(MyEnum) + Q_ENUM(MyEnum) MyEnumFlag fprop() const { return A; } }; void tst_QMetaObjectBuilder::copyMetaObject_metaProperty() { - // The TestMetaPropertyFlags class has both `Q_ENUMS(MyEnum)` and + // The TestMetaPropertyFlags class has both `Q_ENUM(MyEnum)` and // `Q_FLAG(MyEnumFlag, MyEnum)`, which means two separate sets of enumerator data // are generated for `MyEnum`, from the .moc file: // `QtMocHelpers::EnumData` diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp index 10769165ec..d262c99c2e 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetaproperty/tst_qmetaproperty.cpp @@ -54,6 +54,8 @@ private slots: void enumsFlags(); void notifySignalIndex(); void qflags(); + void metaEnums_data(); + void metaEnums(); public: enum EnumType { EnumType1 }; @@ -124,6 +126,66 @@ void tst_QMetaProperty::qflags() QVERIFY(prop.isFlagType()); } +class MyClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(EnumFlags1 prop1 READ prop1) + Q_PROPERTY(Enum1 plainEnum1 READ plainEnum1) + + Q_PROPERTY(QFlags prop2 READ prop2) + Q_PROPERTY(Enum2 plainEnum2 READ plainEnum2) + + Q_PROPERTY(Qt::Alignment outOfScope READ outOfScope) + +public: + enum Enum1 { A = 0x01, B = 0x02 }; + Q_DECLARE_FLAGS(EnumFlags1, Enum1) + Q_FLAG(EnumFlags1) + EnumFlags1 prop1() const { return A; } + Enum1 plainEnum1() const { return A; } + + enum Enum2 { C, D }; + Q_DECLARE_FLAGS(EnumFlags2, Enum2) + Q_FLAG(EnumFlags2) + QFlags prop2() const { return C; } + Enum2 plainEnum2() const { return C; } + + Qt::Alignment outOfScope() const { return {}; } +}; + +void tst_QMetaProperty::metaEnums_data() +{ + QTest::addColumn("propName"); + QTest::addColumn("isFlag"); + + auto addRow = [](const char *name, bool isFlag) { + QTest::newRow(name) << QByteArray(name) << isFlag; + }; + + addRow("prop1", true); + addRow("prop2", true); + addRow("plainEnum1", true); // `true` because we have Q_FLAG(EnumFlags1), no Q_ENUM + addRow("plainEnum2", true); // ditto + addRow("outOfScope", true); +} + +void tst_QMetaProperty::metaEnums() +{ + QFETCH(QByteArray, propName); + QFETCH(bool, isFlag); + + + const QMetaObject *mo = &MyClass::staticMetaObject; + const int idx = mo->indexOfProperty(propName.constData()); + QCOMPARE_NE(idx, -1); + QMetaProperty prop = mo->property(idx); + QEXPECT_FAIL("prop2", + "QMetaProperty with flags type using plain 'QFlags' (no scope prefix) " + "can't find the meta-enum data", + Abort); + QVERIFY(prop.isEnumType()); + QCOMPARE(prop.isFlagType(), isFlag); +} class MyGadget { Q_GADGET diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h index e9a177356e..16efe66650 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.h @@ -231,7 +231,7 @@ struct CustomMovable { friend bool operator==(const CustomMovable &, const CustomMovable &) { return true; } // needed for QSet. We actually check that it makes sense. - friend qsizetype qHash(const CustomMovable &, qsizetype seed = 0) { return seed; } + friend size_t qHash(const CustomMovable &, size_t seed = 0) noexcept { return seed; } }; #if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501 diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/CMakeLists.txt index 6bb3b15850..709168e555 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/CMakeLists.txt @@ -15,6 +15,8 @@ function(addTimerTest test) qt_internal_add_test(${test} SOURCES tst_qtimer.cpp + DEFINES + QT_NO_CAST_FROM_BYTEARRAY LIBRARIES Qt::CorePrivate Qt::TestPrivate diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 98c184872f..5059e62a31 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -186,7 +186,8 @@ void tst_QTimer::singleShotNormalizes() // control test: regular connection { QTimer timer; - QVERIFY(QObject::connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), slotName)); + QVERIFY(QObject::connect(&timer, SIGNAL(timeout()), + &QTestEventLoop::instance(), slotName.constData())); timer.setSingleShot(true); timer.start(1); QTestEventLoop::instance().enterLoop(TestTimeout); @@ -194,20 +195,20 @@ void tst_QTimer::singleShotNormalizes() } // non-zero time - QTimer::singleShot(1, &QTestEventLoop::instance(), slotName); + QTimer::singleShot(1, &QTestEventLoop::instance(), slotName.constData()); QTestEventLoop::instance().enterLoop(TestTimeout); QVERIFY(!QTestEventLoop::instance().timeout()); - QTimer::singleShot(1ms, &QTestEventLoop::instance(), slotName); + QTimer::singleShot(1ms, &QTestEventLoop::instance(), slotName.constData()); QTestEventLoop::instance().enterLoop(TestTimeout); QVERIFY(!QTestEventLoop::instance().timeout()); // zero time - QTimer::singleShot(0, &QTestEventLoop::instance(), slotName); + QTimer::singleShot(0, &QTestEventLoop::instance(), slotName.constData()); QTestEventLoop::instance().enterLoop(TestTimeout); QVERIFY(!QTestEventLoop::instance().timeout()); - QTimer::singleShot(0ms, &QTestEventLoop::instance(), slotName); + QTimer::singleShot(0ms, &QTestEventLoop::instance(), slotName.constData()); QTestEventLoop::instance().enterLoop(TestTimeout); QVERIFY(!QTestEventLoop::instance().timeout()); } diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/relocatable_change.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/relocatable_change.cpp index 89b22fb601..0a2f760e98 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/relocatable_change.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/relocatable_change.cpp @@ -8,6 +8,7 @@ QT_BEGIN_NAMESPACE Q_DECLARE_TYPEINFO(RelocatableInPluginType, Q_RELOCATABLE_TYPE); +QT_WARNING_DISABLE_CLANG("-Wreturn-type-c-linkage") extern "C" QVariant Q_DECL_EXPORT pluginCreateVariant(bool relocatable) { return relocatable ? relocatabilityChange_create() diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 98b2146d7c..209535e7e5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -282,6 +282,9 @@ private slots: void toRectF_data(); void toRectF(); + void qvariant_cast_fromNull_int() { qvariant_cast_fromNull_impl(42); } + void qvariant_cast_fromNull_QString() { qvariant_cast_fromNull_impl(u"string"_s); } + void qvariant_cast_fromNull_QTransform() { qvariant_cast_fromNull_impl(QTransform{1, 2, 3, 4, 5, 6, 7, 8, 9}); } void qvariant_cast_QObject_data(); void qvariant_cast_QObject(); void qvariant_cast_QObject_derived(); @@ -460,6 +463,7 @@ private: QTransform, NonDefaultConstructible >; + template void qvariant_cast_fromNull_impl(T t) const; template void getIf_impl(T t) const; template @@ -476,6 +480,20 @@ private: const qlonglong intMax1 = (qlonglong)INT_MAX + 1; +template +T mutate(const T &t) { return t + t; } +template <> +QTransform mutate(const QTransform &t) +{ + return t * 2; +} + +template +QVariant make_null_QVariant_of_type() +{ + return QVariant(QMetaType::fromType()); +} + void tst_QVariant::constructor() { QVariant variant; @@ -2675,6 +2693,59 @@ void tst_QVariant::cleanupTestCase() qDeleteAll(objectPointerTestData); } +struct NonConvertible +{ + std::array payload; + NonConvertible() + { + payload.fill(-1); + } +}; +template void tst_QVariant::qvariant_cast_fromNull_impl(T t) const +{ + auto operate = [](T &v) { + // some random operations on the type to ensure it is valid + v = mutate(v); + if constexpr (std::is_same_v) + (void)v.toUtf8(); + else if constexpr (std::is_same_v) + (void)v.m11(); + }; + + // create a null QVariant of the same type + QVariant null = make_null_QVariant_of_type(); + + QVERIFY(null.isNull()); + T v = qvariant_cast(null); + QCOMPARE_EQ(v, T{}); + QCOMPARE_NE(v, t); + operate(v); + + // move from null + QVERIFY(null.isNull()); + v = qvariant_cast(std::move(null)); + QCOMPARE_EQ(v, T{}); + QCOMPARE_NE(v, t); + operate(v); + + // repeat, but now make this variant null via failed conversion + null = QVariant::fromValue(NonConvertible{}); + QVERIFY(!null.convert(QMetaType::fromType())); + + QVERIFY(null.isNull()); + v = qvariant_cast(null); + QCOMPARE_EQ(v, T{}); + QCOMPARE_NE(v, t); + operate(v); + + // move from null + QVERIFY(null.isNull()); + v = qvariant_cast(std::move(null)); + QCOMPARE_EQ(v, T{}); + QCOMPARE_NE(v, t); + operate(v); +} + void tst_QVariant::qvariant_cast_QObject_data() { QTest::addColumn("data"); @@ -3248,6 +3319,8 @@ QT_WARNING_POP addComparePair(EnumTest_Enum0_value, 0U); addComparePair(EnumTest_Enum0_value, 0LL); addComparePair(EnumTest_Enum0_value, 0ULL); + addComparePair(EnumTest_Enum0_value, -1); + addComparePair(EnumTest_Enum0_value, -1LL); addComparePair(EnumTest_Enum0_value, int(EnumTest_Enum0_value)); addComparePair(EnumTest_Enum0_value, qint64(EnumTest_Enum0_value)); addComparePair(EnumTest_Enum0_value, quint64(EnumTest_Enum0_value)); @@ -3262,6 +3335,8 @@ QT_WARNING_POP addComparePair(EnumTest_Enum1_value, 0U); addComparePair(EnumTest_Enum1_value, 0LL); addComparePair(EnumTest_Enum1_value, 0ULL); + addComparePair(EnumTest_Enum1_value, -1); + addComparePair(EnumTest_Enum1_value, -1LL); addComparePair(EnumTest_Enum1_value, int(EnumTest_Enum1_value)); addComparePair(EnumTest_Enum1_value, qint64(EnumTest_Enum1_value)); addComparePair(EnumTest_Enum1_value, quint64(EnumTest_Enum1_value)); @@ -3276,6 +3351,8 @@ QT_WARNING_POP addComparePair(EnumTest_Enum3_value, 0U); addComparePair(EnumTest_Enum3_value, 0LL); addComparePair(EnumTest_Enum3_value, 0ULL); + addComparePair(EnumTest_Enum3_value, -1); + addComparePair(EnumTest_Enum3_value, -1LL); addComparePair(EnumTest_Enum3_value, int(EnumTest_Enum3_value)); addComparePair(EnumTest_Enum3_value, qint64(EnumTest_Enum3_value)); addComparePair(EnumTest_Enum3_value, quint64(EnumTest_Enum3_value)); @@ -3286,8 +3363,45 @@ QT_WARNING_POP addComparePair(EnumTest_Enum3_bigValue, qint64(EnumTest_Enum3_bigValue)); addComparePair(EnumTest_Enum3_bigValue, quint64(EnumTest_Enum3_bigValue)); + // unsigned enums + addComparePair(EnumTest_Enum4{}, 0); + addComparePair(EnumTest_Enum4{}, 0U); + addComparePair(EnumTest_Enum4{}, 0LL); + addComparePair(EnumTest_Enum4{}, 0ULL); + addComparePair(EnumTest_Enum4{}, -1); + addComparePair(EnumTest_Enum4{}, -1LL); + addComparePair(EnumTest_Enum4{}, ~0U); + addComparePair(EnumTest_Enum4{}, ~0ULL); + addComparePair(EnumTest_Enum4{}, EnumTest_Enum4(-1)); + + addComparePair(EnumTest_Enum5{}, 0); + addComparePair(EnumTest_Enum5{}, 0U); + addComparePair(EnumTest_Enum5{}, 0LL); + addComparePair(EnumTest_Enum5{}, 0ULL); + addComparePair(EnumTest_Enum5{}, -1); + addComparePair(EnumTest_Enum5{}, -1LL); + addComparePair(EnumTest_Enum5{}, ~0U); + addComparePair(EnumTest_Enum5{}, ~0ULL); + addComparePair(EnumTest_Enum5{}, EnumTest_Enum5(-1)); + + addComparePair(EnumTest_Enum6{}, 0); + addComparePair(EnumTest_Enum6{}, 0U); + addComparePair(EnumTest_Enum6{}, 0LL); + addComparePair(EnumTest_Enum6{}, 0ULL); + addComparePair(EnumTest_Enum6{}, -1); + addComparePair(EnumTest_Enum6{}, -1LL); + addComparePair(EnumTest_Enum6{}, ~0U); + addComparePair(EnumTest_Enum6{}, ~0ULL); + addComparePair(EnumTest_Enum6{}, EnumTest_Enum6(-1)); + // enums of different types always compare as unordered addComparePairWithResult(EnumTest_Enum0_value, EnumTest_Enum1_value, QPartialOrdering::Unordered); + + // QCborSimpleType behaves like quint8 + addComparePairWithResult(QCborSimpleType{}, 0, QPartialOrdering::Equivalent); + addComparePairWithResult(QCborSimpleType{}, -1, QPartialOrdering::Greater); + addComparePairWithResult(QCborSimpleType{0xff}, -128, QPartialOrdering::Greater); + addComparePairWithResult(QCborSimpleType{0xff}, qint8(-128), QPartialOrdering::Greater); } void tst_QVariant::compareNumerics() const @@ -5329,9 +5443,7 @@ static void testSequentialIteration() QCOMPARE(listIter.size(), 6); - if (listIter.canRandomAccessIterate()) - sortIterable(&listIter); - else if (listIter.canReverseIterate()) + if (listIter.canReverseIterate()) sortIterable(&listIter); else if (listIter.canForwardIterate()) return; // std::sort cannot sort with only forward iterators. @@ -7002,25 +7114,12 @@ void tst_QVariant::pointerAndReferenceSpecialMemberFunctions() } } -template -T mutate(const T &t) { return t + t; } -template <> -QTransform mutate(const QTransform &t) -{ - return t * 2; -} template <> NonDefaultConstructible mutate(const NonDefaultConstructible &t) { return NonDefaultConstructible{t.i + t.i}; } -template -QVariant make_null_QVariant_of_type() -{ - return QVariant(QMetaType::fromType()); -} - template void tst_QVariant::getIf_impl(T t) const { diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/text/qlocale/tst_qlocale.cpp index 22e3fcb1ad..6c2dc2a5fd 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/text/qlocale/tst_qlocale.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/text/qlocale/tst_qlocale.cpp @@ -2571,7 +2571,7 @@ void tst_QLocale::toDateTime_data() << "cs_CZ" << QDateTime(QDate(1945, 8, 15), QTime(12, 0)) << "yyyy-MM-dd hh:mm aP" << "1945-08-15 12:00 OdP." << true; - const QDateTime dt(QDate(2017, 02, 25), QTime(17, 21, 25)); + const QDateTime dt(QDate(2017, 2, 25), QTime(17, 21, 25)); // These formats correspond to the locale formats, with the timezone removed. // We hardcode them in case an update to the locale DB changes them. @@ -2608,13 +2608,14 @@ void tst_QLocale::toDateTime_data() QTest::newRow("tr:short") << "tr" << dt.addSecs(-25) << "d.MM.yyyy HH:mm" << "25.02.2017 17:21" << true; + const QDateTime dtOld(QDate(1917, 2, 25), QTime(17, 21)); // A century before dt. QTest::newRow("ccp:short") - << "ccp" << dt << "dd/M/yy h:mm AP" - // "𑄸𑄻/𑄸/𑄷𑄽 𑄻:𑄸𑄷 PM" + << "ccp" << dtOld << u"dd/M/yy h:mm AP"_s + // "𑄸𑄻/𑄸/𑄷𑄽 𑄻:𑄸𑄷 PM" -> "25/2/17 5:25 PM" (using default century, 1900) << QString::fromUcs4(U"\U00011138\U0001113b/\U00011138/\U00011137\U0001113d \U0001113b:" U"\U00011138\U00011137 PM") << true; QTest::newRow("ccp:long") - << "ccp" << dt << "dddd, d MMMM, yyyy h:mm:ss AP" + << "ccp" << dt << u"dddd, d MMMM, yyyy h:mm:ss AP"_s // "𑄥𑄧𑄚𑄨𑄝𑄢𑄴, 𑄸𑄻 𑄜𑄬𑄛𑄴𑄝𑄳𑄢𑄪𑄠𑄢𑄨, 𑄸𑄶𑄷𑄽 𑄻:𑄸𑄷:𑄸𑄻 PM" << QString::fromUcs4(U"\U00011125\U00011127\U0001111a\U00011128\U0001111d\U00011122" U"\U00011134, \U00011138\U0001113b \U0001111c\U0001112c\U0001111b" @@ -2791,7 +2792,7 @@ void tst_QLocale::toDate_data() QTest::newRow("shortFormat") // Use of two-digit year considered harmful. << usa << QDate(1909, 1, 5) << u"M/d/yy"_s << u"1/5/09"_s << true; - const QDate date(2017, 02, 25); + const QDate date(2017, 2, 25); QTest::newRow("C:long") << C << date << "dddd, d MMMM yyyy" << u"Saturday, 25 February 2017"_s << true; QTest::newRow("C:short") @@ -2828,13 +2829,14 @@ void tst_QLocale::toDate_data() QTest::newRow("tr:short") << turk << date << u"d.MM.yyyy"_s << u"25.02.2017"_s << true; + const QDate midWar(1917, 2, 25); // A century before date. const QLocale chakma{QLocale::Chakma}; QTest::newRow("ccp:short") - << chakma << date << "dd/M/yy" + << chakma << midWar << u"dd/M/yy"_s // Two-digit yeaar, default century is 1900 // "𑄸𑄻/𑄸/𑄷𑄽" << QString::fromUcs4(U"\U00011138\U0001113b/\U00011138/\U00011137\U0001113d") << true; QTest::newRow("ccp:long") - << chakma << date << "dddd, d MMMM, yyyy" + << chakma << date << u"dddd, d MMMM, yyyy"_s // "𑄥𑄧𑄚𑄨𑄝𑄢𑄴, 𑄸𑄻 𑄜𑄬𑄛𑄴𑄝𑄳𑄢𑄪𑄠𑄢𑄨, 𑄸𑄶𑄷𑄽" << QString::fromUcs4(U"\U00011125\U00011127\U0001111a\U00011128\U0001111d\U00011122" U"\U00011134, \U00011138\U0001113b \U0001111c\U0001112c\U0001111b" @@ -2979,11 +2981,11 @@ void tst_QLocale::toTime_data() const QLocale chakma{QLocale::Chakma}; QTest::newRow("ccp:short") - << chakma << time << "h:mm AP" + << chakma << QTime(17, 21) << u"h:mm AP"_s // "𑄸𑄻/𑄸/𑄷𑄽 𑄻:𑄸𑄷 PM" << QString::fromUcs4(U"\U0001113b:\U00011138\U00011137 PM") << true; QTest::newRow("ccp:long") - << chakma << time << "h:mm:ss AP" + << chakma << time << u"h:mm:ss AP"_s // "𑄻:𑄸𑄷:𑄸𑄻 PM" << QString::fromUcs4(U"\U0001113b:\U00011138\U00011137:\U00011138\U0001113b PM") << true; } diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/CMakeLists.txt index 14d8d7dd40..9413e92ae4 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/CMakeLists.txt @@ -19,9 +19,15 @@ qt_internal_add_test(tst_qthreadstorage ## Scopes: ##################################################################### -if(NOT ANDROID) +if(QT_FEATURE_process AND NOT ANDROID) add_subdirectory(crashonexit) - if(QT_FEATURE_process) - add_dependencies(tst_qthreadstorage crashOnExit_helper) - endif() + add_dependencies(tst_qthreadstorage crashOnExit_helper) + + qt_internal_add_executable(tst_qthreadstorage_warnonexit + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qthreadstorage/crashOnExit_helper" + SOURCES + warnonexit.cpp + ) + add_dependencies(tst_qthreadstorage tst_qthreadstorage_warnonexit) endif() diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp index e3734d27f7..d42f017b38 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/thread/qthreadstorage/tst_qthreadstorage.cpp @@ -36,6 +36,7 @@ private slots: void autoDelete(); void adoptedThreads(); void ensureCleanupOrder(); + void noWarningOnExitForQGlobalStatic(); void crashOnExit(); void leakInDestructor(); void resetInDestructor(); @@ -249,6 +250,29 @@ void tst_QThreadStorage::ensureCleanupOrder() QVERIFY(First::order < Second::order); } +void tst_QThreadStorage::noWarningOnExitForQGlobalStatic() +{ +#ifdef Q_OS_ANDROID + QSKIP("Can't start QProcess to run a custom user binary on Android"); +#endif +#if !QT_CONFIG(process) + QSKIP("No QProcess support"); +#else +# ifdef Q_OS_WIN + QSKIP("Not able to detect a call to exit() in Windows."); + QString binary = QFINDTESTDATA("tst_qthreadstorage_warnonexit.exe"); +# else + QString binary = QFINDTESTDATA("tst_qthreadstorage_warnonexit"); +# endif + QProcess process; + process.start(binary); + QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); + QVERIFY2(process.waitForFinished(), qPrintable(process.errorString())); + QCOMPARE(process.readAllStandardError(), QByteArray()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); +#endif +} + #if QT_CONFIG(process) static inline bool runCrashOnExit(const QString &binary, QString *errorMessage) { diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/CMakeLists.txt index 2f045c386e..44c56bd8a3 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/CMakeLists.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/CMakeLists.txt @@ -33,7 +33,6 @@ add_subdirectory(qmessageauthenticationcode) if(NOT INTEGRITY) add_subdirectory(qoffsetstringarray) endif() -add_subdirectory(qpair) add_subdirectory(qpoint) add_subdirectory(qpointf) add_subdirectory(qqueue) diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/collections/tst_collections.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/collections/tst_collections.cpp index cbe04ae39f..0debfaf5e5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/collections/tst_collections.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/collections/tst_collections.cpp @@ -153,6 +153,8 @@ struct Dummy { bool operator==(const Dummy &) const { return false; } bool operator<(const Dummy &) const { return false; } + + friend size_t qHash(const Dummy &, size_t seed = 0) noexcept { return seed; } }; struct RecursiveList : public QList @@ -226,12 +228,11 @@ struct NoCmpRecursiveMultiHashK : public QMultiHash; @@ -3309,9 +3307,9 @@ template class C> void QTBUG13079_collectionInsideCollect } -size_t qHash(const QTBUG13079_Node &) +size_t qHash(const QTBUG13079_Node &, size_t seed = 0) noexcept { - return 0; + return seed; } bool operator==(const QTBUG13079_Node &a, const QTBUG13079_Node &b) diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp index 441ee8a04f..57b08e33db 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qarraydata/tst_qarraydata.cpp @@ -1105,7 +1105,7 @@ void tst_QArrayData::arrayOpsExtra() o->appendInitialize(initialSize); } else { // there's no prependInitialize() - for (qsizetype n = 0; n < initialSize; ++n) { + for (size_t n = 0; n < initialSize; ++n) { i->emplace(0); s->emplace(0); o->emplace(0); diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qcache/tst_qcache.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qcache/tst_qcache.cpp index 5fccb8f1d0..125ca68db7 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qcache/tst_qcache.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qcache/tst_qcache.cpp @@ -355,6 +355,9 @@ struct KeyType private: KeyType &operator=(const KeyType &); + + friend size_t qHash(const KeyType &key, size_t seed = 0) noexcept + { return qHash(key.foo, seed); } }; struct ValueType @@ -373,11 +376,6 @@ bool operator==(const KeyType &key1, const KeyType &key2) return key1.foo == key2.foo; } -size_t qHash(const KeyType &key) -{ - return qHash(key.foo); -} - void tst_QCache::axioms_on_key_type() { QCache foo; diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhash/tst_qhash.cpp index 8ec9cb516d..f4a21b93ab 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhash/tst_qhash.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhash/tst_qhash.cpp @@ -1,6 +1,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include +#ifdef QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD +# undef QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD // this file tests the 1-to-2-arg adapter +#endif + #include #include diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp index 76d9f8f21e..5ce2707bad 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp @@ -34,6 +34,7 @@ public slots: void init(); private Q_SLOTS: + void pointerConsistency(); void boolIntegerConsistency(); void unsignedIntegerConsistency_data(); void unsignedIntegerConsistency(); @@ -77,6 +78,51 @@ private Q_SLOTS: #endif }; +void tst_QHashFunctions::pointerConsistency() +{ + // const/mutable + { + int i = 0; + const auto h = qHash(&i, seed); + if (seed != 0) QEXPECT_FAIL("", "QTBUG-116074", Continue); + QCOMPARE(h, qHash(&std::as_const(i), seed)); + } + + // QObject base/derived (should all hash like a QObject*): + { + QFile file; + QObject *o = &file; + const QObject *co = &file; + const auto h = qHash(&file, seed); + QCOMPARE(h, qHash( o, seed)); + if (seed != 0) QEXPECT_FAIL("", "QTBUG-116074", Continue); + QCOMPARE(h, qHash(co, seed)); + } + + // multiple inheritance (there is nothing we can do anything about this): + { + struct Base1 { int i; virtual ~Base1() = default; }; + struct Base2 { long long i; virtual ~Base2() = default; }; + struct MultipleInheritance : Base1, Base2 {}; + + MultipleInheritance mi; + Base1 *b1 = &mi; + Base2 *b2 = &mi; + const Base1 *cb1 = &mi; + const Base2 *cb2 = &mi; + const auto h = qHash(&mi, seed); + QCOMPARE(&mi, b1); + QCOMPARE(h, qHash( b1, seed)); + QCOMPARE(&mi, b2); + //QCOMPARE(h, qHash( b2, seed)); // requires pointer adjustment + QCOMPARE(&mi, cb1); + if (seed != 0) QEXPECT_FAIL("", "QTBUG-116074", Continue); + QCOMPARE(h, qHash(cb1, seed)); + QCOMPARE(&mi, cb2); + // QCOMPARE(h, qHash(cb2, seed)); // requires pointer adjustment + } +} + void tst_QHashFunctions::initTestCase() { QTest::addColumn("seedValue"); diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qmap/tst_qmap.cpp index 21ac2ccc14..7a123e3b7e 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qmap/tst_qmap.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qmap/tst_qmap.cpp @@ -42,6 +42,7 @@ private slots: void lowerUpperBound(); void mergeCompare(); void take(); + void takeAlwaysDetaches(); void iterators(); void multimapIterators(); @@ -1173,6 +1174,7 @@ void tst_QMap::take() QCOMPARE(map.take(3), QLatin1String("drei")); QVERIFY(!map.contains(3)); + QVERIFY(map.take(3).isNull()); } { @@ -1194,6 +1196,71 @@ void tst_QMap::take() } } +void tst_QMap::takeAlwaysDetaches() +{ + { + const QMap ref = {{0, 1}, {2, 3}}; + QMap map = {{0, 1}, {2, 3}}; + const auto copy = map; + QVERIFY(copy.isSharedWith(map)); + [[maybe_unused]] const auto r = map.take(42); // doesn't exist + QVERIFY(map.isDetached()); // but detached + QVERIFY(!copy.isSharedWith(map)); + QCOMPARE_EQ(map, ref); + QCOMPARE_EQ(copy, ref); + } + { + const QMultiMap ref = {{0, 1}, {0, 2}}; + QMultiMap map = {{0, 1}, {0, 2}}; + const auto copy = map; + QVERIFY(copy.isSharedWith(map)); + [[maybe_unused]] const auto r = map.take(42); // doesn't exist + QVERIFY(map.isDetached()); // but detached + QVERIFY(!copy.isSharedWith(map)); + QCOMPARE_EQ(map, ref); + QCOMPARE_EQ(copy, ref); + } + + // except on null: + + { + QMap ref; + QMap null; + QVERIFY(ref.isSharedWith(null)); + [[maybe_unused]] const auto r = null.take(42); + QVERIFY(ref.isSharedWith(null)); + } + { + QMultiMap ref; + QMultiMap null; + QVERIFY(ref.isSharedWith(null)); + [[maybe_unused]] const auto r = null.take(42); + QVERIFY(ref.isSharedWith(null)); + } + + // but also on empty: + + { + QMap empty = {{0, 0}}; + // this makes it empty: + [[maybe_unused]] const auto r = empty.take(0); + const auto copy = empty; + QVERIFY(copy.isSharedWith(empty)); + [[maybe_unused]] const auto r2 = empty.take(42); + QVERIFY(!copy.isSharedWith(empty)); + } + + { + QMultiMap empty = {{0, 0}}; + // this makes it empty: + [[maybe_unused]] const auto r = empty.take(0); + const auto copy = empty; + QVERIFY(copy.isSharedWith(empty)); + [[maybe_unused]] const auto r2 = empty.take(42); + QVERIFY(!copy.isSharedWith(empty)); + } +} + void tst_QMap::iterators() { QMap map; diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp index 736e9ae434..6910a9a82b 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qoffsetstringarray/tst_qoffsetstringarray.cpp @@ -24,6 +24,7 @@ constexpr const auto messages = qOffsetStringArray( "level - 3", "level - 4" ); +static_assert(messages.MaxElementLength == std::char_traits::length("level - 0")); // When compiled with C++20, this is using the native char8_t constexpr auto utf8Messages = qOffsetStringArray( @@ -33,6 +34,7 @@ constexpr auto utf8Messages = qOffsetStringArray( u8"level - 3", u8"level - 4" ); +static_assert(utf8Messages.MaxElementLength == std::char_traits::length("level - 0")); constexpr auto utf16Messages = qOffsetStringArray( u"level - 0", @@ -41,6 +43,7 @@ constexpr auto utf16Messages = qOffsetStringArray( u"level - 3", u"level - 4" ); +static_assert(utf16Messages.MaxElementLength == std::char_traits::length("level - 0")); constexpr const auto messages257 = qOffsetStringArray( "", "", "", "", "", "", "", "", "", "", @@ -72,6 +75,7 @@ constexpr const auto messages257 = qOffsetStringArray( "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "end" ); +static_assert(messages257.MaxElementLength == std::char_traits::length("end")); constexpr const auto messagesBigOffsets = qOffsetStringArray( " 10 20 30 40 50 60 70 80 90", @@ -79,6 +83,7 @@ constexpr const auto messagesBigOffsets = qOffsetStringArray( " 10 20 30 40 50 60 70 80 90", " 10 20 30 40 50 60 70 80 90" ); +static_assert(messagesBigOffsets.MaxElementLength == 90); void tst_QOffsetStringArray::init() { diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/CMakeLists.txt b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/CMakeLists.txt deleted file mode 100644 index 2dd048e015..0000000000 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -##################################################################### -## tst_qpair Test: -##################################################################### - -if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) - cmake_minimum_required(VERSION 3.16) - project(tst_qpair LANGUAGES CXX) - find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) -endif() - -qt_internal_add_test(tst_qpair - SOURCES - tst_qpair.cpp -) - -## Scopes: -##################################################################### diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/tst_qpair.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/tst_qpair.cpp deleted file mode 100644 index 0c9d87bb01..0000000000 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qpair/tst_qpair.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only - -#include - -#include -#include - -class tst_QPair : public QObject -{ - Q_OBJECT -private Q_SLOTS: - void pairOfReferences(); - void structuredBindings(); - void testConstexpr(); - void testConversions(); - void taskQTBUG_48780_pairContainingCArray(); - void testDeductionRules(); -}; - -class C { C() {} ~C() {} Q_DECL_UNUSED_MEMBER char _[4]; }; -class M { M() {} Q_DECL_UNUSED_MEMBER char _[4]; }; -class P { Q_DECL_UNUSED_MEMBER char _[4]; }; - -QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(M, Q_RELOCATABLE_TYPE); -Q_DECLARE_TYPEINFO(P, Q_PRIMITIVE_TYPE); -QT_END_NAMESPACE - -// avoid the comma: -typedef QPair QPairCC; -typedef QPair QPairCM; -typedef QPair QPairCP; -typedef QPair QPairMC; -typedef QPair QPairMM; -typedef QPair QPairMP; -typedef QPair QPairPC; -typedef QPair QPairPM; -typedef QPair QPairPP; - -static_assert( QTypeInfo::isComplex); -static_assert( !QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( !QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( !QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( !QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( !QTypeInfo::isRelocatable ); - -static_assert( QTypeInfo::isComplex); -static_assert( QTypeInfo::isRelocatable ); - -static_assert(!QTypeInfo::isComplex); -static_assert( QTypeInfo::isRelocatable ); - -static_assert(!std::is_pointer_v); - - -void tst_QPair::pairOfReferences() -{ - int i = 0; - QString s; - - QPair p(i, s); - - p.first = 1; - QCOMPARE(i, 1); - - i = 2; - QCOMPARE(p.first, 2); - - p.second = QLatin1String("Hello"); - QCOMPARE(s, QLatin1String("Hello")); - - s = QLatin1String("olleH"); - QCOMPARE(p.second, QLatin1String("olleH")); - - QPair q = p; - q.first = 3; - QCOMPARE(i, 3); - QCOMPARE(p.first, 3); - - q.second = QLatin1String("World"); - QCOMPARE(s, QLatin1String("World")); - QCOMPARE(p.second, QLatin1String("World")); -} - -void tst_QPair::structuredBindings() -{ - using PV = QPair; - using PR = QPair; - - { - PV pv = {42, "Hello"}; - PR pr = {pv.first, pv.second}; - - auto [fv, sv] = pv; - - fv = 24; - sv = "World"; - QCOMPARE(fv, 24); - QCOMPARE(sv, "World"); - QCOMPARE(pv.first, 42); - QCOMPARE(pv.second, "Hello"); - - auto [fr, sr] = pr; - - fr = 2424; - // sr = "World"; // const - QCOMPARE(fr, 2424); - QCOMPARE(pv.first, 2424); - } - - { - PV pv = {42, "Hello"}; - PR pr = {pv.first, pv.second}; - - auto& [fv, sv] = pv; - - fv = 24; - sv = "World"; - QCOMPARE(fv, 24); - QCOMPARE(sv, "World"); - QCOMPARE(pv.first, 24); - QCOMPARE(pv.second, "World"); - - auto& [fr, sr] = pr; - - fr = 4242; - //sr = "2World"; // const - - QCOMPARE(fr, 4242); - QCOMPARE(pr.first, 4242); - QCOMPARE(pv.first, 4242); - } -} - -void tst_QPair::testConstexpr() -{ - constexpr QPair pID = qMakePair(0, 0.0); - Q_UNUSED(pID); - - constexpr QPair pDD = qMakePair(0.0, 0.0); - constexpr QPair pDD2 = qMakePair(0, 0.0); // involes (rvalue) conversion ctor - constexpr bool equal = pDD2 == pDD; - QVERIFY(equal); - - constexpr QPair pSI = qMakePair(QSize(4, 5), 6); - Q_UNUSED(pSI); -} - -void tst_QPair::testConversions() -{ - // construction from lvalue: - { - const QPair rhs(42, 4.5); - const QPair pii = rhs; - QCOMPARE(pii.first, 42); - QCOMPARE(pii.second, 4); - - const QPair pif = rhs; - QCOMPARE(pif.first, 42); - QCOMPARE(pif.second, 4.5f); - } - - // assignment from lvalue: - { - const QPair rhs(42, 4.5); - QPair pii; - pii = rhs; - QCOMPARE(pii.first, 42); - QCOMPARE(pii.second, 4); - - QPair pif; - pif = rhs; - QCOMPARE(pif.first, 42); - QCOMPARE(pif.second, 4.5f); - } - - // construction from rvalue: - { -#define rhs qMakePair(42, 4.5) - const QPair pii = rhs; - QCOMPARE(pii.first, 42); - QCOMPARE(pii.second, 4); - - const QPair pif = rhs; - QCOMPARE(pif.first, 42); - QCOMPARE(pif.second, 4.5f); -#undef rhs - } - - // assignment from rvalue: - { -#define rhs qMakePair(42, 4.5) - QPair pii; - pii = rhs; - QCOMPARE(pii.first, 42); - QCOMPARE(pii.second, 4); - - QPair pif; - pif = rhs; - QCOMPARE(pif.first, 42); - QCOMPARE(pif.second, 4.5f); -#undef rhs - } -} - -void tst_QPair::taskQTBUG_48780_pairContainingCArray() -{ - // compile-only: - QPair pair; - pair.first[0] = 0; - pair.first[1] = 1; - pair.second = 2; - Q_UNUSED(pair); -} - -void tst_QPair::testDeductionRules() -{ -#if defined(__cpp_deduction_guides) && __cpp_deduction_guides >= 201907L - QPair p1{1, 2}; - static_assert(std::is_same::value); - static_assert(std::is_same::value); - QCOMPARE(p1.first, 1); - QCOMPARE(p1.second, 2); - - QPair p2{QString("string"), 2}; - static_assert(std::is_same::value); - static_assert(std::is_same::value); - QCOMPARE(p2.first, "string"); - QCOMPARE(p2.second, 2); - - QPair p3(p2); - static_assert(std::is_same::value); - static_assert(std::is_same::value); - QCOMPARE(p3.first, "string"); - QCOMPARE(p3.second, 2); -#else - QSKIP("Unsupported (requires C++20's CTAD for aliases)"); -#endif -} - -QTEST_APPLESS_MAIN(tst_QPair) -#include "tst_qpair.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qset/tst_qset.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qset/tst_qset.cpp index fae63cccd6..9d668211c5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qset/tst_qset.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qset/tst_qset.cpp @@ -62,9 +62,10 @@ private: struct IdentityTracker { int value, id; + friend size_t qHash(IdentityTracker key, size_t seed = 0) + { return qHash(key.value, seed); } }; -inline size_t qHash(IdentityTracker key) { return qHash(key.value); } inline bool operator==(IdentityTracker lhs, IdentityTracker rhs) { return lhs.value == rhs.value; } void tst_QSet::comparisonCompiles() diff --git a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp index 459bce09df..84e14dc1a4 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/corelib/tools/qvarlengtharray/tst_qvarlengtharray.cpp @@ -298,6 +298,19 @@ void tst_QVarLengthArray::move(T t1, T t2) QCOMPARE(v.size(), 2); QCOMPARE(v[0], t1); QCOMPARE(v[1], t2); + + QVarLengthArray v2; + v2.append(t1); + v2.append(t1); + v2.append(t2); + v2.append(t2); + + v = std::move(v2); + QCOMPARE(v.size(), 4); + QCOMPARE(v[0], t1); + QCOMPARE(v[1], t1); + QCOMPARE(v[2], t2); + QCOMPARE(v[3], t2); } } diff --git a/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/myobject.h b/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/myobject.h index 59410e763e..d958f1208b 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/myobject.h +++ b/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/myobject.h @@ -8,6 +8,7 @@ #include #include #include +#include class MyObject: public QObject, protected QDBusContext { @@ -16,6 +17,7 @@ class MyObject: public QObject, protected QDBusContext Q_CLASSINFO("D-Bus Introspection", "" " \n" " \n" +" \n" " \n" " \n" " \n" @@ -58,6 +60,7 @@ class MyObject: public QObject, protected QDBusContext "") Q_PROPERTY(int prop1 READ prop1 WRITE setProp1) Q_PROPERTY(QList complexProp READ complexProp WRITE setComplexProp) + Q_PROPERTY(int delayedProp READ delayedProp) public: static int callCount; @@ -96,6 +99,23 @@ public: m_complexProp = value; } + int delayedProp() const + { + Q_ASSERT(QDBusContext::calledFromDBus()); + + setDelayedReply(true); + + QMetaObject::invokeMethod( + const_cast(this), + [message = message(), connection = connection()] { + auto reply = message.createReply(QVariant::fromValue(QDBusVariant(5))); + connection.send(reply); + }, + Qt::QueuedConnection); + + return 0; + } + Q_INVOKABLE void ping_invokable(QDBusMessage msg) { Q_ASSERT(QDBusContext::calledFromDBus()); diff --git a/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp b/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp index 803ae4fa0f..18290f58fb 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/dbus/qdbusinterface/tst_qdbusinterface.cpp @@ -194,6 +194,8 @@ private slots: void complexPropertyRead(); void complexPropertyWrite(); + void delayedPropertyReadPeer(); + void propertyReadPeer(); void propertyWritePeer(); void complexPropertyReadPeer(); @@ -359,7 +361,7 @@ void tst_QDBusInterface::introspect() QCOMPARE(mo->methodCount() - mo->methodOffset(), 7); QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1); - QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2); + QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 3); QVERIFY(mo->indexOfProperty("prop1") != -1); QVERIFY(mo->indexOfProperty("complexProp") != -1); } @@ -689,7 +691,7 @@ void tst_QDBusInterface::introspectPeer() QCOMPARE(mo->methodCount() - mo->methodOffset(), 7); QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1); - QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2); + QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 3); QVERIFY(mo->indexOfProperty("prop1") != -1); QVERIFY(mo->indexOfProperty("complexProp") != -1); } @@ -1066,6 +1068,19 @@ void tst_QDBusInterface::complexPropertyWrite() QCOMPARE(obj.m_complexProp, arg); } +void tst_QDBusInterface::delayedPropertyReadPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), TEST_INTERFACE_NAME, con); + + resetPeer(); + + QVariant v = iface.property("delayedProp"); + QVERIFY(v.isValid()); + QCOMPARE(v.userType(), int(QMetaType::Int)); + QCOMPARE(v.toInt(), 5); +} + void tst_QDBusInterface::propertyReadPeer() { QDBusConnection con("peer"); diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/itemmodels/qfilesystemmodel/tst_qfilesystemmodel.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/itemmodels/qfilesystemmodel/tst_qfilesystemmodel.cpp index 3a668233bf..ff6d366994 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/itemmodels/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/itemmodels/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -119,7 +119,9 @@ private slots: #ifdef Q_OS_WIN void correctFileInfoForDriveRootPath(); + void fileInfoPathNoDoubleSlashUNC(); #endif + void fileInfoPathNoDoubleSlash(); protected: bool createFiles(QFileSystemModel *model, const QString &test_path, @@ -1407,8 +1409,41 @@ void tst_QFileSystemModel::correctFileInfoForDriveRootPath() QCOMPARE(info.absoluteFilePath(), slashDrive); QCOMPARE(info.absolutePath(), slashDrive); } + +void tst_QFileSystemModel::fileInfoPathNoDoubleSlashUNC() +{ + // Verify that UNC paths are not affected by the double slash fix. + // UNC paths are handled before the loop in QFileSystemModelPrivate::node(), + // so the fix should have no impact on them. + QFileSystemModel model; + const QModelIndex idx = model.setRootPath(u"//localhost/c$"_s); + if (!idx.isValid()) + QSKIP("UNC path //localhost/c$ is not accessible on this machine"); + + const QString resultPath = model.fileInfo(idx).filePath(); + QVERIFY2(!resultPath.startsWith("///"_L1), + qPrintable("fileInfo() returned UNC path with triple slash: " + resultPath)); + QCOMPARE(resultPath, u"//localhost/c$"_s); +} #endif +void tst_QFileSystemModel::fileInfoPathNoDoubleSlash() +{ + const QString dirPath = flatDirTestPath; + QDir dir(dirPath); + const QString subdir = QStringLiteral("subdir"); + QVERIFY(dir.mkdir(subdir)); + const QString subdirPath = dir.absoluteFilePath(subdir); + + QFileSystemModel model; + const QModelIndex idx = model.setRootPath(subdirPath); + + const QString resultPath = model.fileInfo(idx).filePath(); + QVERIFY2(!resultPath.startsWith("//"_L1), + qPrintable("fileInfo() returned path with double slash: " + resultPath)); + QCOMPARE(resultPath, subdirPath); +} + QTEST_MAIN(tst_QFileSystemModel) #include "tst_qfilesystemmodel.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp index e61bc97049..479924fbc3 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qclipboard/tst_qclipboard.cpp @@ -74,6 +74,21 @@ void tst_QClipboard::init() const QString testdataDir = QFileInfo(QFINDTESTDATA("copier")).absolutePath(); QVERIFY2(QDir::setCurrent(testdataDir), qPrintable("Could not chdir to " + testdataDir)); #endif +#if defined(Q_OS_QNX) + QDir clipboardDir("clipboard"); + + if (!clipboardDir.exists()) { + QVERIFY2(clipboardDir.mkpath("."), "Failed to create clipboard directory"); + } + + QFile file("clipboard/.qnxclipboard"); + if (!file.exists()) { + QVERIFY2(file.open(QIODevice::WriteOnly), "Failed to create .qnxclipboard"); + file.close(); + } + + qputenv("QQNX_CLIPBOARD", QFile::encodeName(clipboardDir.absolutePath())); +#endif } Q_DECLARE_METATYPE(QClipboard::Mode) @@ -218,6 +233,9 @@ static bool runHelper(const QString &program, const QStringList &arguments, QByt #if QT_CONFIG(process) QProcess process; process.setProcessChannelMode(QProcess::ForwardedChannels); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert(QStringLiteral("QT_QPA_PLATFORM"), QGuiApplication::platformName()); + process.setProcessEnvironment(env); process.start(program, arguments); if (!process.waitForStarted()) { *errorMessage = "Unable to start '" + program.toLocal8Bit() + " ': " @@ -267,6 +285,8 @@ void tst_QClipboard::copy_exit_paste() // ### It's still possible to test copy/paste - just keep the apps running if (!PlatformClipboard::isAvailable()) QSKIP("Native clipboard not working in this setup"); + if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive)) + QSKIP("Offscreen platform does not support cross-process clipboard"); const QString stringArgument(QStringLiteral("Test string.")); QByteArray errorMessage; QVERIFY2(runHelper(QStringLiteral("copier/copier"), QStringList(stringArgument), &errorMessage), @@ -287,6 +307,8 @@ void tst_QClipboard::copyImage() #if QT_CONFIG(process) if (!PlatformClipboard::isAvailable()) QSKIP("Native clipboard not working in this setup"); + if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive)) + QSKIP("Offscreen platform does not support cross-process clipboard"); QImage image(100, 100, QImage::Format_ARGB32); image.fill(QColor(Qt::transparent)); image.setPixel(QPoint(1, 0), QColor(Qt::blue).rgba()); diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qguiapplication/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qguiapplication/BLACKLIST index 3fa6c4880b..c60c12bd9c 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qguiapplication/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qguiapplication/BLACKLIST @@ -1,2 +1,5 @@ [quitOnLastWindowClosedWithEventLoopLocker] b2qt + +[changeFocusWindow] +wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index 004eaa61de..4f3e557561 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -57,6 +57,9 @@ private slots: void platformSurface(); void isExposed(); void isActive(); +#if defined(Q_OS_WIN) + void activateTopLevelOnClickWhenFocusInDescendant(); +#endif void testInputEvents(); void touchToMouseTranslation(); void touchToMouseTranslationForDevices(); @@ -107,6 +110,7 @@ private slots: void enterLeaveOnWindowShowHide(); #endif void windowExposedAfterReparent(); + void childGeometryAfterReparent(); void childEvents(); void parentEvents(); @@ -424,8 +428,13 @@ void tst_QWindow::eventOrderOnShow() window.show(); QCoreApplication::processEvents(); + int safeMarginsEventCount = 0; + connect(&window, &QWindow::safeAreaMarginsChanged, this, [&]() { + ++safeMarginsEventCount; + }); + QTRY_COMPARE(window.received(QEvent::Show), 1); - QTRY_COMPARE(window.received(QEvent::Resize), 1); + QTRY_COMPARE(window.received(QEvent::Resize) - safeMarginsEventCount, 1); QTRY_VERIFY(window.isExposed()); QVERIFY(window.eventIndex(QEvent::Show) < window.eventIndex(QEvent::Resize)); @@ -1051,6 +1060,55 @@ void tst_QWindow::isActive() QVERIFY(child.isActive()); } +#if defined(Q_OS_WIN) +// QTBUG-130754: with a native child window focused, clicking the parent +// top-level must restore focus to the top-level. Windows does not send +// WM_MOUSEACTIVATE to an already-active top-level, so the Windows QPA +// has to detect this case on MouseButtonPress and activate the top-level +// manually. +void tst_QWindow::activateTopLevelOnClickWhenFocusInDescendant() +{ + if (QGuiApplication::platformName().compare(QStringLiteral("windows"), Qt::CaseInsensitive)) + QSKIP("Windows-specific test"); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("QWindow::requestActivate() is not supported."); + + Window parent; + parent.setTitle(QLatin1String(QTest::currentTestFunction())); + parent.setGeometry(QRect(m_availableTopLeft + QPoint(80, 80), m_testWindowSize)); + parent.show(); + QVERIFY(QTest::qWaitForWindowExposed(&parent)); + QTRY_COMPARE(QGuiApplication::focusWindow(), &parent); + + Window child; + child.setParent(&parent); + // Keep the child in a corner so the injected press below lands on + // the parent's client area, not on the child HWND. + child.setGeometry(10, 10, 40, 40); + child.show(); + QTRY_VERIFY(child.isExposed()); + + child.requestActivate(); + QTRY_COMPARE(QGuiApplication::focusWindow(), &child); + QVERIFY(parent.isActive()); + + parent.reset(); + + // PostMessage bypasses the cursor input subsystem, so Windows does + // not generate a WM_MOUSEACTIVATE for the parent - exactly the + // scenario that used to leave focus stuck on the child. + const HWND parentHwnd = reinterpret_cast(parent.winId()); + const QPoint clickPos(parent.width() / 2, parent.height() / 2); + const LPARAM lp = MAKELPARAM(clickPos.x(), clickPos.y()); + PostMessage(parentHwnd, WM_LBUTTONDOWN, MK_LBUTTON, lp); + PostMessage(parentHwnd, WM_LBUTTONUP, 0, lp); + + QTRY_COMPARE(QGuiApplication::focusWindow(), &parent); + QVERIFY(parent.isActive()); + QVERIFY(parent.received(QEvent::FocusIn) >= 1); +} +#endif + class InputTestWindow : public ColoredWindow { public: @@ -2997,9 +3055,6 @@ void tst_QWindow::keepPendingUpdateRequests() void tst_QWindow::activateDeactivateEvent() { - if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) - QSKIP("QWindow::requestActivate() is not supported."); - class Window : public QWindow { public: @@ -3028,13 +3083,11 @@ void tst_QWindow::activateDeactivateEvent() Window w2; w1.show(); - w1.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&w1)); QCOMPARE(w1.activateCount, 1); QCOMPARE(w1.deactivateCount, 0); w2.show(); - w2.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&w2)); QCOMPARE(w1.deactivateCount, 1); QCOMPARE(w2.activateCount, 1); @@ -3287,6 +3340,63 @@ void tst_QWindow::windowExposedAfterReparent() QVERIFY(QTest::qWaitForWindowExposed(&child)); } +void tst_QWindow::childGeometryAfterReparent() +{ + if (isPlatformEglFS()) + QSKIP("eglfs does not support child windows."); + + if (QGuiApplication::platformName() == QStringLiteral("xcb")) + QSKIP("Behavior currently broken on X11: QTBUG-143664"); + +#ifdef Q_OS_ANDROID + QSKIP("Fails on Android. QTBUG-105201"); +#endif + + const QRect topLevelChildGeometry(m_availableTopLeft + QPoint(50, 50), m_testWindowSize); + + // QTBUG-143663: When a window is shown as top-level and then reparented to + // become a child, its geometry should be correct. Previously on Windows, + // stale frame margins from the top-level state were incorrectly applied. + + ColoredWindow parent(Qt::green); + parent.setTitle(QLatin1String(QTest::currentTestFunction())); + parent.setGeometry(QRect(m_availableTopLeft, m_testWindowSize * 2)); + parent.show(); + QVERIFY(QTest::qWaitForWindowExposed(&parent)); + + // Show as top-level first (this is the key to reproducing the bug) + ColoredWindow child(Qt::red); + child.setGeometry(topLevelChildGeometry); + child.show(); + QVERIFY(QTest::qWaitForWindowExposed(&child)); + + // Check initial geometry. Window has a frame, so geometry != frameGeometry + QTRY_COMPARE(child.geometry(), topLevelChildGeometry); + QCOMPARE_NE(child.frameGeometry(), child.geometry()); + QCOMPARE(child.position(), topLevelChildGeometry.topLeft()); + QCOMPARE_NE(child.framePosition(), m_availableTopLeft); + + // Reparent to become a child window + child.setParent(&parent); + child.setGeometry(0, 0, 100, 100); + + // Child windows have no frame, so geometry == frameGeometry + QTRY_COMPARE(child.geometry(), QRect(0, 0, 100, 100)); + QCOMPARE(child.frameGeometry(), child.geometry()); + QCOMPARE(child.position(), QPoint(0, 0)); + QCOMPARE(child.framePosition(), QPoint(0, 0)); + + // Reparent to become a top level window + child.setParent(nullptr); + child.setGeometry(topLevelChildGeometry); + + // Window has a frame, so geometry != frameGeometry + QTRY_COMPARE(child.geometry(), topLevelChildGeometry); + QCOMPARE_NE(child.frameGeometry(), child.geometry()); + QCOMPARE(child.position(), topLevelChildGeometry.topLeft()); + QCOMPARE_NE(child.framePosition(), m_availableTopLeft); +} + struct ParentWindow : public QWindow { bool event(QEvent *event) override @@ -3448,4 +3558,3 @@ void tst_QWindow::parentEvents() #include QTEST_MAIN(tst_QWindow) - diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/qopengl/tst_qopengl.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/qopengl/tst_qopengl.cpp index 36ff1d1f2e..cc574987b3 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -86,6 +86,7 @@ private slots: void bufferCreate(); void bufferMapRange(); void defaultQGLCurrentBuffer(); + void makeCurrentAfterResizeWithNonDefaultFBOBound(); #if QT_CONFIG(egl) void dontCrashOnInvalidContextThreadTeardown(); #endif @@ -1781,6 +1782,74 @@ void tst_QOpenGL::dontCrashOnInvalidContextThreadTeardown() } #endif +// QTBUG-143779: On macOS, when a window has been resized, QOpenGLContext::makeCurrent() +// does a lazy update of the context, which recreates the window's default FBO and any +// associcated structures. If client code has a different FBO bound at this point, the +// update logic fails to set up these internal structures, and we end up crashing when +// we later swap. This test checks that a makeCurrent after a resize doesn't crash, and +// that the user's FBO is still bound. +void tst_QOpenGL::makeCurrentAfterResizeWithNonDefaultFBOBound() +{ + class FBOWindow : public QWindow + { + public: + FBOWindow() { + QSurfaceFormat format; + format.setSamples(4); + + setSurfaceType(QWindow::OpenGLSurface); + setFormat(format); + create(); + + context.reset(new QOpenGLContext); + context->setFormat(format); + QVERIFY(context->create()); + QVERIFY(context->makeCurrent(this)); + fbo.reset(new QOpenGLFramebufferObject(64, 64)); + fbo->bind(); + } + + void exposeEvent(QExposeEvent *) override + { + ++paintCount; + + // If FBO was bound in a previous frame we shouldn't crash + QVERIFY(context->makeCurrent(this)); + + // makeCurrent shouldn't affect the bound FBO + QVERIFY(fbo->isBound()); + + // Temporarily bind the default FBO, and render to it + auto *f = context->functions(); + fbo->release(); + f->glClearColor(1.0, 0.0, 0.0, 1.0); + f->glClear(GL_COLOR_BUFFER_BIT); + context->swapBuffers(this); + + // Then rebind the non-default FBO bound for next frame + fbo->bind(); + } + + QScopedPointer context; + QScopedPointer fbo; + int paintCount = 0; + }; + + FBOWindow window; + + if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QOpenGLFramebufferObject not supported on this platform"); + + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + for (int i = 0; i < 10; ++i) { + int paintCount = window.paintCount; + window.resize(window.width() + 1, 600); + QTRY_VERIFY(window.paintCount > paintCount); + } +} + QTEST_MAIN(tst_QOpenGL) #include "tst_qopengl.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/data/buildshaders.bat b/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/data/buildshaders.bat index 3111f8d36a..601e2a5e52 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/data/buildshaders.bat +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/data/buildshaders.bat @@ -33,3 +33,5 @@ qsb --glsl "300 es,330" --hlsl 61 -c --msl 12 multiview.frag -o multiview.frag.q qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o samesrb_1.vert.qsb samesrb_1.vert qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o samesrb_2.vert.qsb samesrb_2.vert qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o samesrb.frag.qsb samesrb.frag +qsb --glsl "150,130,300 es" --hlsl 50 --msl 12 -o fullscreenquad.vert.qsb fullscreenquad.vert +qsb --glsl "150,130,300 es" --hlsl 50 --msl 12 -o fullscreenquad_color.frag.qsb fullscreenquad_color.frag diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index 1d7153f9ea..59e839d7ab 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -128,6 +128,8 @@ private slots: void renderToTextureArrayMultiView(); void renderToTextureSameSrbDifferentShaders_data(); void renderToTextureSameSrbDifferentShaders(); + void renderToTextureScissorChange_data(); + void renderToTextureScissorChange(); void renderToWindowSimple_data(); void renderToWindowSimple(); void continuousReadbackFromWindow_data(); @@ -4067,6 +4069,157 @@ void tst_QRhi::renderToTextureArrayMultiView() } } +void tst_QRhi::renderToTextureScissorChange_data() +{ + rhiTestData(); +} + +void tst_QRhi::renderToTextureScissorChange() +{ + QFETCH(QRhi::Implementation, impl); + QFETCH(QRhiInitParams *, initParams); + + std::unique_ptr rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr)); + if (!rhi) + QSKIP("QRhi could not be created, skipping testing rendering"); + +#ifdef TST_GL + if (impl == QRhi::OpenGLES2) { + rhi->makeThreadLocalNativeContextCurrent(); + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + // because of gl_VertexId in the shader, which is added in GLSL 130 and GLSL ES 300 + if (!ctx || ctx->format().majorVersion() < 3) + QSKIP("This test needs at least OpenGL 3.0 or OpenGL ES 3.0, skipping on OpenGL"); + } +#endif + + const QSize outputSize(1920, 1080); + std::unique_ptr texture(rhi->newTexture(QRhiTexture::RGBA8, outputSize, 1, + QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); + QVERIFY(texture->create()); + + std::unique_ptr rt(rhi->newTextureRenderTarget({ texture.get() })); + std::unique_ptr rpDesc(rt->newCompatibleRenderPassDescriptor()); + rt->setRenderPassDescriptor(rpDesc.get()); + QVERIFY(rt->create()); + + QRhiCommandBuffer *cb = nullptr; + QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess); + QVERIFY(cb); + + QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch(); + + std::unique_ptr ubuf(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 16)); + QVERIFY(ubuf->create()); + QVector4D color = { 1.0f, 0.0f, 0.0f, 1.0f }; + updates->updateDynamicBuffer(ubuf.get(), 0, 16, &color); + + std::unique_ptr srb(rhi->newShaderResourceBindings()); + srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, ubuf.get()), + }); + QVERIFY(srb->create()); + + auto setupPipeline = [&srb, &rpDesc](QRhiGraphicsPipeline *pipeline) { + QShader vs = loadShader(":/data/fullscreenquad.vert.qsb"); + QShader fs = loadShader(":/data/fullscreenquad_color.frag.qsb"); + pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); + pipeline->setShaderResourceBindings(srb.get()); + pipeline->setRenderPassDescriptor(rpDesc.get()); + }; + + std::unique_ptr pipeline(rhi->newGraphicsPipeline()); + setupPipeline(pipeline.get()); + QVERIFY(pipeline->create()); + + std::unique_ptr scissoringPipeline(rhi->newGraphicsPipeline()); + setupPipeline(scissoringPipeline.get()); + scissoringPipeline->setFlags(QRhiGraphicsPipeline::UsesScissor); + QVERIFY(scissoringPipeline->create()); + + cb->beginPass(rt.get(), Qt::white, { 1.0f, 0 }, updates); + // fullscreen quad, scissored to (bottom-left) 100x100 - 300x300 + cb->setGraphicsPipeline(scissoringPipeline.get()); + cb->setViewport({ 0, 0, float(outputSize.width()), float(outputSize.height()) }); + cb->setShaderResources(); + cb->setScissor({ 100, 100, 200, 200 }); + cb->draw(3); + cb->endPass(); + + QRhiReadbackResult readResult; + QImage result; + readResult.completed = [&readResult, &result] { + result = QImage(reinterpret_cast(readResult.data.constData()), + readResult.pixelSize.width(), readResult.pixelSize.height(), + QImage::Format_RGBA8888_Premultiplied); // non-owning, no copy needed because readResult outlives result + }; + QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.get() }, &readResult); + cb->resourceUpdate(readbackBatch); + rhi->finish(); + + if (rhi->isYUpInFramebuffer()) + result = result.flipped(); + + if (rhi->backend() != QRhi::Null) { + // 200x200 red rect at (bottom left) 100,100 + int y = outputSize.height() - 1 - 150; + int redCount = 0; + for (int x = 100; x < 100 + 300; ++x) { + QRgb c = result.pixel(x, y); + if (qRed(c) >= 254 && qGreen(c) == 0 && qBlue(c) == 0) + ++redCount; + } + QVERIFY(redCount == 200); + + // should be white outside the scissor rect + y = outputSize.height() - 50; + redCount = 0; + for (int x = 100; x < 100 + 300; ++x) { + QRgb c = result.pixel(x, y); + if (qRed(c) >= 254 && qGreen(c) == 0 && qBlue(c) == 0) + ++redCount; + } + QCOMPARE(redCount, 0); + } + + cb->beginPass(rt.get(), Qt::white, { 1.0f, 0 }); + + // fullscreen quad, scissored to (bottom-left) 100x100 - 300x300 + cb->setGraphicsPipeline(scissoringPipeline.get()); + cb->setViewport({ 0, 0, float(outputSize.width()), float(outputSize.height()) }); + cb->setShaderResources(); + cb->setScissor({ 100, 100, 200, 200 }); + cb->draw(3); + + // switch to the non-UsesScissor pipeline, the end result should be the whole textured filled with red, + // the scissoring is expected to be "disabled" (or made to match the viewport) automatically + cb->setGraphicsPipeline(pipeline.get()); + cb->setShaderResources(); + cb->draw(3); + + cb->endPass(); + + readbackBatch = rhi->nextResourceUpdateBatch(); + readbackBatch->readBackTexture({ texture.get() }, &readResult); + cb->resourceUpdate(readbackBatch); + rhi->finish(); + + if (rhi->backend() != QRhi::Null) { + const int y = outputSize.height() - 1 - 150; + // no scissoring, everything is supposed to be red + int nonRedCount = 0; + for (int x = 100; x < 100 + 300; ++x) { + QRgb c = result.pixel(x, y); + if (!(qRed(c) >= 254 && qGreen(c) == 0 && qBlue(c) == 0)) + ++nonRedCount; + } + QVERIFY(nonRedCount == 0); + } + + rhi->endOffscreenFrame(); +} + void tst_QRhi::renderToWindowSimple_data() { rhiTestData(); diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index ccf833d273..5e4f9411d5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -74,6 +74,8 @@ private slots: void addApplicationFontFallback(); void addApplicationEmojiFontFamily(); + void propertiesForStyleName(); + private: QString m_ledFont; QString m_testFont; @@ -868,5 +870,27 @@ void tst_QFontDatabase::addApplicationEmojiFontFamily() } +void tst_QFontDatabase::propertiesForStyleName() +{ + const QString family = QStringLiteral("Arial"); + const QString style = QStringLiteral("Bold Italic"); + + if (!QFontDatabase::families().contains(family) + || !QFontDatabase::styles(family).contains(style)) { + QSKIP("This test requires Arial Bold Italic to be installed on the system."); + } + + QFont f(family); + f.setStyleName(style); + + QFontInfo fi(f); + QCOMPARE(fi.family(), family); + QCOMPARE(fi.styleName(), style); + QCOMPARE(fi.weight(), QFont::Bold); + QCOMPARE(fi.style(), QFont::StyleItalic); + QCOMPARE(fi.italic(), true); + QCOMPARE(fi.bold(), true); +} + QTEST_MAIN(tst_QFontDatabase) #include "tst_qfontdatabase.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index a831b36af6..7e3d930f01 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -1259,10 +1259,17 @@ void tst_QTextDocumentFragment::html_listIndent() QCOMPARE(cursor.currentList()->format().indent(), 4); } -void tst_QTextDocumentFragment::html_listNestedParagraphIndent() +void tst_QTextDocumentFragment::html_listNestedParagraphIndent() // QTBUG-143122 QTBUG-144216 { - const char html[] = "
    • Blah

      exposition

    "; + const char html[] = "
    • Blah

      exposition

    NOT indented

    "; cursor.insertFragment(QTextDocumentFragment::fromHtml(html)); + + // Check the paragraph after the end of the list: should not be indented (QTBUG-144216) + QCOMPARE(cursor.block().text(), "NOT indented"); + QCOMPARE(cursor.blockFormat().indent(), 0); + + // Go back and check the paragraph inside the list item + cursor.movePosition(QTextCursor::PreviousBlock); QCOMPARE(cursor.block().text(), "exposition"); // The paragraph happens to not be "inside" the list item, as declared: perhaps that's another bug QCOMPARE(cursor.currentList(), nullptr); diff --git a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp index 2ae31849bf..5340781f62 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp @@ -42,6 +42,7 @@ private slots: void largeImage(); #endif + void wrapTextWithSpacesAndTabs(); private: QTextDocument *doc; @@ -429,5 +430,28 @@ void tst_QTextDocumentLayout::testHitTest() } #endif +void tst_QTextDocumentLayout::wrapTextWithSpacesAndTabs() +{ + doc->clear(); + + QTextOption option = doc->defaultTextOption(); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + doc->setDefaultTextOption(option); + doc->setTextWidth(200); + + QTextCursor cursor(doc); + // Spaces followed by tab create specific width that triggers overflow handling + cursor.insertText(QString(70, ' ') + QStringLiteral("\t") + QStringLiteral("text")); + + doc->documentLayout()->documentSize(); + + QTextBlock block = doc->firstBlock(); + QVERIFY(block.isValid()); + + // Verify wrap mode is correctly restored to WrapAtWordBoundaryOrAnywhere + QCOMPARE(block.layout()->textOption().wrapMode(), + QTextOption::WrapAtWordBoundaryOrAnywhere); +} + QTEST_MAIN(tst_QTextDocumentLayout) #include "tst_qtextdocumentlayout.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/local/recipes/qt/qtbase/source/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index 95f067a66e..b87306f898 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -51,6 +51,56 @@ private: }; #if QT_CONFIG(networkdiskcache) +class ReadTrackingDevice final : public QIODevice +{ +public: + ReadTrackingDevice(QIODevice *device, bool *readOccurred, QObject *parent = nullptr) + : QIODevice(parent), wrapped(device), consumed(readOccurred) + { + Q_ASSERT(wrapped); + wrapped->setParent(this); + if (!wrapped->isOpen()) + wrapped->open(QIODevice::ReadOnly); + setOpenMode(wrapped->openMode()); + } + + bool isSequential() const override { return wrapped->isSequential(); } + bool atEnd() const override { return wrapped->atEnd(); } + qint64 size() const override { return wrapped->size(); } + qint64 pos() const override { return wrapped->pos(); } + bool seek(qint64 pos) override { return wrapped->seek(pos); } + bool canReadLine() const override { return wrapped->canReadLine() || QIODevice::canReadLine(); } + qint64 bytesAvailable() const override { return wrapped->bytesAvailable() + QIODevice::bytesAvailable(); } + bool waitForReadyRead(int msecs) override { return wrapped->waitForReadyRead(msecs); } + bool waitForBytesWritten(int msecs) override { return wrapped->waitForBytesWritten(msecs); } + +protected: + qint64 readData(char *data, qint64 maxSize) override + { + const qint64 bytesRead = wrapped->read(data, maxSize); + if (bytesRead > 0) + *consumed = true; + return bytesRead; + } + + qint64 readLineData(char *data, qint64 maxSize) override + { + const qint64 bytesRead = wrapped->readLine(data, maxSize); + if (bytesRead > 0) + *consumed = true; + return bytesRead; + } + + qint64 writeData(const char *data, qint64 maxSize) override + { + return wrapped->write(data, maxSize); + } + +private: + QIODevice *wrapped; + bool *consumed; +}; + class NetworkDiskCache : public QNetworkDiskCache { Q_OBJECT @@ -66,8 +116,10 @@ public: QIODevice *data(const QUrl &url) override { - gotData = true; - return QNetworkDiskCache::data(url); + QIODevice *device = QNetworkDiskCache::data(url); + if (!device) + return nullptr; + return new ReadTrackingDevice(device, &gotData); } QTemporaryDir tempDir; diff --git a/local/recipes/qt/qtbase/source/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp b/local/recipes/qt/qtbase/source/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp index 977a047c58..b851470e6d 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp @@ -16,6 +16,7 @@ using namespace Qt::StringLiterals; + /* The tests here are meant to be self-contained, using servers in the same process if needed. This enables externals to more easily run the tests too. @@ -23,11 +24,18 @@ using namespace Qt::StringLiterals; class tst_QNetworkReply_local : public QObject { Q_OBJECT + enum Method { + Get, + Put, + Post, + Custom, + }; private slots: void initTestCase_data(); void get(); - void post(); + void requestWithPayload_data(); + void requestWithPayload(); void emptyDeviceUpload_data(); void emptyDeviceUpload(); @@ -97,8 +105,24 @@ void tst_QNetworkReply_local::get() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); } -void tst_QNetworkReply_local::post() +void tst_QNetworkReply_local::requestWithPayload_data() { + QTest::addColumn("method"); + QTest::addColumn("customVerb"); + QTest::addRow("get") << Put << ""; + QTest::addRow("put") << Put << ""; + QTest::addRow("post") << Post << ""; + QTest::addRow("custom-get") << Custom << "get"; + QTest::addRow("custom-put") << Custom << "put"; + QTest::addRow("custom-post") << Custom << "post"; + QTest::addRow("custom-delete") << Custom << "delete"; +} + + +void tst_QNetworkReply_local::requestWithPayload() +{ + QFETCH(const Method, method); + QFETCH(const QString, customVerb); std::unique_ptr server = getServerForCurrentScheme(); const QUrl url = getUrlForCurrentScheme(server.get()); @@ -106,7 +130,21 @@ void tst_QNetworkReply_local::post() const QByteArray payload = "Hello from the other side!"_ba; QNetworkRequest req(url); req.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); - std::unique_ptr reply(manager.post(req, payload)); + auto reply = [&]() -> std::unique_ptr { + using unique_ptr = std::unique_ptr; + switch (method) { + case Get: + return unique_ptr{ manager.get(req, payload) }; + case Put: + return unique_ptr{ manager.put(req, payload) }; + case Post: + return unique_ptr{ manager.post(req, payload) }; + case Custom: + return unique_ptr{ manager.sendCustomRequest(req, customVerb.toUtf8(), + payload) }; + } + Q_UNREACHABLE_RETURN({}); + }(); const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); }); QVERIFY(res); @@ -125,12 +163,6 @@ void tst_QNetworkReply_local::post() QCOMPARE(firstRequest.receivedData.last(payload.size() + 4), "\r\n\r\n" + payload); } -enum Method { - Get, - Put, - Post, - Custom, -}; void tst_QNetworkReply_local::emptyDeviceUpload_data() { QTest::addColumn("method"); diff --git a/local/recipes/qt/qtbase/source/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/local/recipes/qt/qtbase/source/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp index a52099b5b4..f533905a35 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp @@ -39,6 +39,7 @@ private slots: // void tcpLoopbackPerformance(); void passwordAuth(); void ensureEofTriggersNotification(); + void readNotificationStall(); protected slots: void tcpSocketNonBlocking_hostFound(); @@ -743,5 +744,87 @@ void tst_QHttpSocketEngine::ensureEofTriggersNotification() QCOMPARE(socket.state(), QTcpSocket::UnconnectedState); } +//---------------------------------------------------------------------------------- + +void tst_QHttpSocketEngine::readNotificationStall() +{ + // QTBUG-113749: With HTTPS through HTTP CONNECT proxy, read notifications + // can stall when the read buffer is smaller than the engine's internal buffer. + // + // In production: + // - QHttpNetworkConnectionChannel sets sslSocket->setReadBufferSize(64*1024) + // - QHttpSocketEngine::connectInternal() sets inner socket buffer to 65536 + // - Schannel's transmit() reads in 16KB chunks, stops when its decrypted + // buffer fills to 64KB, leaving encrypted data in the outer buffer + // - canReadNotification() does a partial read from the engine + // - setReadNotificationEnabled(true) early-returns, data stranded, stall + // + // We reproduce this without TLS by using a small read buffer (16KB) on a + // plain QTcpSocket through a fake HTTP CONNECT proxy, forcing partial reads. + + const int readBufferSize = 16 * 1024; + const int totalSize = 64 * 1024 * 10; + const QByteArray payload(totalSize, 'A'); + + // Fake HTTP CONNECT proxy: accepts CONNECT, then sends payload in one burst + QTcpServer proxyServer; + QVERIFY(proxyServer.listen(QHostAddress::LocalHost)); + + QTcpSocket *serverSide = nullptr; + + connect(&proxyServer, &QTcpServer::newConnection, this, [&]() { + serverSide = proxyServer.nextPendingConnection(); + connect(serverSide, &QTcpSocket::readyRead, this, [&]() { + if (!serverSide->peek(serverSide->bytesAvailable()).contains("\r\n\r\n")) + return; + serverSide->readAll(); + serverSide->write("HTTP/1.0 200 Connection established\r\n\r\n"); + serverSide->write(payload); + disconnect(serverSide, &QTcpSocket::readyRead, nullptr, nullptr); + serverSide->disconnectFromHost(); + }); + }); + + QTcpSocket socket; + connect(&socket, SIGNAL(connected()), SLOT(exitLoopSlot())); + socket.setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort())); + socket.connectToHost("0.1.2.3", 12345); + + QTestEventLoop::instance().enterLoop(5); + if (QTestEventLoop::instance().timeout()) + QFAIL("Connect timed out"); + QCOMPARE(socket.state(), QTcpSocket::ConnectedState); + + // Use a buffer smaller than the engine's internal 65536 to force partial reads + socket.setReadBufferSize(readBufferSize); + + QByteArray received; + int readyReadCount = 0; + + connect(&socket, &QTcpSocket::readyRead, this, [&]() { + received += socket.readAll(); + ++readyReadCount; + if (received.size() >= totalSize) + QTestEventLoop::instance().exitLoop(); + }); + + connect(&socket, &QTcpSocket::disconnected, this, [&]() { + if (socket.bytesAvailable() > 0) + received += socket.readAll(); + QTestEventLoop::instance().exitLoop(); + }); + + QTestEventLoop::instance().enterLoop(10); + + if (QTestEventLoop::instance().timeout()) { + QFAIL(qPrintable(QString("QTBUG-113749: Download stalled at %1 of %2 bytes (%3%)") + .arg(received.size()) + .arg(totalSize) + .arg(100.0 * received.size() / totalSize, 0, 'f', 1))); + } + + QCOMPARE_GE(received.size(), totalSize); +} + QTEST_MAIN(tst_QHttpSocketEngine) #include "tst_qhttpsocketengine.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/local/recipes/qt/qtbase/source/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index f21fb37f0e..d8d531f571 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -2530,8 +2530,14 @@ void tst_QTcpSocket::suddenRemoteDisconnect() QString processExe = stressTestDir + "/stressTest"; + auto noMsgPatternEnv = QProcessEnvironment::systemEnvironment(); + // Unset any custom message pattern that might mess with the expected output: + noMsgPatternEnv.remove(u"QT_MESSAGE_PATTERN"_s); + // Start server QProcess serverProcess; + serverProcess.setProcessEnvironment(noMsgPatternEnv); + serverProcess.setReadChannel(QProcess::StandardError); serverProcess.start(processExe, QStringList(server), QIODevice::ReadWrite | QIODevice::Text); QVERIFY2(serverProcess.waitForStarted(), qPrintable( @@ -2552,6 +2558,7 @@ void tst_QTcpSocket::suddenRemoteDisconnect() // Start client QProcess clientProcess; + clientProcess.setProcessEnvironment(noMsgPatternEnv); clientProcess.setReadChannel(QProcess::StandardError); clientProcess.start(processExe, QStringList(client), QIODevice::ReadWrite | QIODevice::Text); QVERIFY2(clientProcess.waitForStarted(), qPrintable( diff --git a/local/recipes/qt/qtbase/source/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp b/local/recipes/qt/qtbase/source/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp index 7abce59b79..5656591cfc 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp @@ -93,9 +93,9 @@ void userConfirmationRequestedNative(JNIEnv *, jobject, jstring callId, int erro emit handler->confirmationRequest(errorCode, QJniObject(errorMessage).toString()); } -void downloadProgressChangedNative(JNIEnv *, jobject, jstring callId, long bytes, long total) +void downloadProgressChangedNative(JNIEnv *, jobject, jstring callId, jlong bytes, jlong total) { - qDebug("Download progress changed %ld/%ld.", bytes, total); + qDebug() << "Download progress changed" << bytes << "/" << total; auto *handler = loaderInstance->findHandler(callId); if (!handler) return; diff --git a/local/recipes/qt/qtbase/source/tests/auto/other/qfocusevent/tst_qfocusevent.cpp b/local/recipes/qt/qtbase/source/tests/auto/other/qfocusevent/tst_qfocusevent.cpp index b4cfb0f4f7..9f13d53122 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/other/qfocusevent/tst_qfocusevent.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/other/qfocusevent/tst_qfocusevent.cpp @@ -81,9 +81,6 @@ private: void tst_QFocusEvent::initTestCase() { - if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) - QSKIP("QWindow::requestActivate() is not supported on this platform."); - testFocusWidget = new QWidget( nullptr ); childFocusWidgetOne = new FocusLineEdit( testFocusWidget ); childFocusWidgetOne->setGeometry( 10, 10, 180, 20 ); diff --git a/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/BLACKLIST index d6b6afeb46..cc73c5a04e 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/BLACKLIST @@ -1,3 +1,5 @@ # QTBUG-130742 [taskQTBUG4497_reusePrinterOnDifferentFiles] vxworks +[testPrintPreviewDialog] +wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp b/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp index d82d175e84..c7d2484cba 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp @@ -91,6 +91,7 @@ private slots: void testPageMetrics_data(); void testPageMetrics(); void reusePageMetrics(); + void customPageSizePaintMetrics(); #endif private: QString testFileName(const QString &prefix, const QString &suffix); @@ -1745,6 +1746,43 @@ void tst_QPrinter::reusePageMetrics() QCOMPARE(defaultP.pageLayout().pageSize().sizePoints(), unavailableSizeToSet.sizePoints()); } +void tst_QPrinter::customPageSizePaintMetrics() +{ + // QTBUG-142745: When a custom page size is set, the paint rect should match + // that size. On Windows, GetDeviceCaps() can return the default paper size + // instead of the custom one, which makes the paint rect shrink or stretch + // to fit the default paper. + QPrinter printer; + printer.setOutputFormat(QPrinter::NativeFormat); + if (printer.outputFormat() != QPrinter::NativeFormat) + QSKIP("This test requires a native printer"); + + // Pick a custom page size that is very different from standard sizes + const QSizeF customSizeMM(100.0, 300.0); + printer.setPageSize(QPageSize(customSizeMM, QPageSize::Millimeter)); + printer.setFullPage(true); + + // width()/height() read from the engine's cached paint rect (m_paintRectPixels), + // but pageRect(DevicePixel) is calculated fresh from the page layout. + // These two should give the same result for custom page sizes. + const QRectF pageRectPixels = printer.pageRect(QPrinter::DevicePixel); + QCOMPARE(printer.width(), int(pageRectPixels.width())); + QCOMPARE(printer.height(), int(pageRectPixels.height())); + + // The aspect ratio should match the custom size, not the default paper + const qreal expectedRatio = customSizeMM.width() / customSizeMM.height(); + const qreal actualRatio = qreal(printer.width()) / printer.height(); + QVERIFY2(qAbs(actualRatio - expectedRatio) < 0.01, + qPrintable(QString("Aspect ratio mismatch: expected %1, got %2") + .arg(expectedRatio).arg(actualRatio))); + + // Same check in landscape + printer.setPageOrientation(QPageLayout::Landscape); + const QRectF landscapeRectPixels = printer.pageRect(QPrinter::DevicePixel); + QCOMPARE(printer.width(), int(landscapeRectPixels.width())); + QCOMPARE(printer.height(), int(landscapeRectPixels.height())); +} + #endif // QT_CONFIG(printer) QTEST_MAIN(tst_QPrinter) diff --git a/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/expected_selected.txt b/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/expected_selected.txt index 9da33d6f9b..6cafbc650f 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/expected_selected.txt +++ b/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/expected_selected.txt @@ -2,5 +2,18 @@ Config: Using QtTest library FAIL! : tst_Selected::excell() Function not found: excell FAIL! : tst_Selected::surprise() Function not found: surprise -Totals: 0 passed, 2 failed, 0 skipped, 0 blacklisted, 0ms +PASS : tst_Selected::initTestCase() +PASS : tst_Selected::pass(verify) +FAIL! : tst_Selected::fail(less) The computed value is expected to be less than the baseline, but is not + Computed (1): 1 + Baseline (0): 0 + Loc: [qtbase/tests/auto/testlib/selftests/selected/tst_selected.cpp(0)] +FAIL! : tst_Selected::fail() Data tag not found: seriously +XFAIL : tst_Selected::xfail(differ) This test should XFAIL + Loc: [qtbase/tests/auto/testlib/selftests/selected/tst_selected.cpp(0)] +PASS : tst_Selected::xfail(differ) +XPASS : tst_Selected::xpass(same) QCOMPARE_EQ(0, 0) returned TRUE unexpectedly. + Loc: [qtbase/tests/auto/testlib/selftests/selected/tst_selected.cpp(0)] +PASS : tst_Selected::cleanupTestCase() +Totals: 4 passed, 5 failed, 0 skipped, 0 blacklisted, 0ms ********* Finished testing of tst_Selected ********* diff --git a/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/tst_selftests.cpp b/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/tst_selftests.cpp index a64eeeedeb..36c9c947b5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/testlib/selftests/tst_selftests.cpp @@ -1003,8 +1003,9 @@ static QProcessEnvironment testEnvironment() // Avoid interference from any qtlogging.ini files, e.g. in /etc/xdg/QtProject/: environment.insert("QT_LOGGING_RULES", "*.debug=true;qt.*=false"); -#if defined(Q_OS_UNIX) +#if defined(Q_OS_UNIX) && (!defined(__QNX__) || __QNX__ < 800) // Avoid the warning from QCoreApplication + // (QNX 8.0+ throws during initialisation; see QTBUG-145975). environment.insert("LC_ALL", "en_US.UTF-8"); #endif diff --git a/local/recipes/qt/qtbase/source/tests/auto/tools/moc/single-quote-digit-separator-n3781.h b/local/recipes/qt/qtbase/source/tests/auto/tools/moc/single-quote-digit-separator-n3781.h index f272ecbddf..c00d9b0dd6 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/tools/moc/single-quote-digit-separator-n3781.h +++ b/local/recipes/qt/qtbase/source/tests/auto/tools/moc/single-quote-digit-separator-n3781.h @@ -19,6 +19,6 @@ public: = 1'234'567 #endif }; - Q_ENUMS(Salaries) + Q_ENUM(Salaries) }; #endif // SINGLE_QUOTE_DIGIT_SEPARATOR_N3781_H diff --git a/local/recipes/qt/qtbase/source/tests/auto/tools/moc/tst_moc.cpp b/local/recipes/qt/qtbase/source/tests/auto/tools/moc/tst_moc.cpp index 9ff6fc3444..8d2fe90bc9 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/tools/moc/tst_moc.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/tools/moc/tst_moc.cpp @@ -3511,13 +3511,14 @@ void tst_Moc::overloadedAddressOperator() class CustomQObject : public QObject { Q_OBJECT - Q_ENUMS(Number) public: enum Number { Zero, One, Two }; + Q_ENUM(Number) + explicit CustomQObject(QObject *parent = nullptr) : QObject(parent) { @@ -3551,13 +3552,14 @@ Q_DECLARE_METATYPE(SomeNamespace::NamespacedNonQObject) class CustomQObject2 : public QObject { Q_OBJECT - Q_ENUMS(Number) public: enum Number { Zero, One, Two }; + Q_ENUM(Number) + explicit CustomQObject2(QObject *parent = nullptr) : QObject(parent) { @@ -4044,9 +4046,9 @@ namespace QTBUG32933_relatedObjectsDontIncludeItself { Q_PROPERTY(Obj::MyEnum p2 MEMBER member) Q_PROPERTY(NS::Obj::MyEnum p3 MEMBER member) Q_PROPERTY(QTBUG32933_relatedObjectsDontIncludeItself::NS::Obj::MyEnum p4 MEMBER member) - Q_ENUMS(MyEnum) public: enum MyEnum { Something, SomethingElse }; + Q_ENUM(MyEnum) MyEnum member; }; } @@ -4056,19 +4058,19 @@ void tst_Moc::QTBUG32933_relatedObjectsDontIncludeItself() { const QMetaObject *mo = &QTBUG32933_relatedObjectsDontIncludeItself::NS::Obj::staticMetaObject; const auto *objects = mo->d.relatedMetaObjects; - // the related objects should be empty because the enums is in the same object. + // the related objects should be empty because the enum is in the same object. QVERIFY(!objects); } class UnrelatedClass : public QObject { Q_OBJECT - Q_ENUMS(UnrelatedEnum) public: enum UnrelatedEnum { UnrelatedInvalidValue = -1, UnrelatedValue = 42 }; + Q_ENUM(UnrelatedEnum) }; // The presence of this macro used to confuse moc and prevent diff --git a/local/recipes/qt/qtbase/source/tests/auto/tools/rcc/data/legal/rcc_legal.cpp b/local/recipes/qt/qtbase/source/tests/auto/tools/rcc/data/legal/rcc_legal.cpp index 248ab2e3b4..b09d93ae3f 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/tools/rcc/data/legal/rcc_legal.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/tools/rcc/data/legal/rcc_legal.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2024 Intel Corporation. ** SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only ** -** Created by: The Resource Compiler for Qt version 6.11.0 +** Created by: The Resource Compiler for Qt version 6.11.1 ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp index 381872c46b..f8efdee5b8 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qdialog/tst_qdialog.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ private slots: void toolDialogPosition(); void deleteMainDefault(); void deleteInExec(); + void execBlocksEvenIfRecreated(); #if QT_CONFIG(sizegrip) void showSizeGrip(); #endif @@ -374,6 +376,38 @@ void tst_QDialog::deleteInExec() QCOMPARE(dialog->exec(), int(QDialog::Rejected)); } + +class RecreatedDialog : public QDialog { + int tId = -1; +public: + bool didBlock = false; + + void showEvent(QShowEvent* ) override + { + QTimer::singleShot(0, [this] { + auto rhiWidget = new QRhiWidget(); + rhiWidget->setParent(this); + }); + tId = startTimer(300); + } + + void timerEvent(QTimerEvent *event) override + { + if (tId == event->timerId()) { + killTimer(tId); + didBlock = true; + accept(); + } + } +}; + +void tst_QDialog::execBlocksEvenIfRecreated() +{ + RecreatedDialog dialog; + QCOMPARE(dialog.exec(), QDialog::Accepted); + QVERIFY(dialog.didBlock); +} + #if QT_CONFIG(sizegrip) void tst_QDialog::showSizeGrip() diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp index 136c789abd..64e8dd4a8a 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qinputdialog/tst_qinputdialog.cpp @@ -496,7 +496,6 @@ void tst_QInputDialog::setDoubleStep_data() QTest::newRow("step 2.0") << 0.0 << 10.0 << 0 << 2.0 << 2.0; QTest::newRow("step 2.5") << 0.5 << 10.5 << 1 << 2.5 << 3.0; QTest::newRow("step 2.25") << 10.05 << 20.05 << 2 << 2.25 << 12.30; - QTest::newRow("step 2.25 fewer decimals") << 0.5 << 10.5 << 1 << 2.25 << 2.75; } void tst_QInputDialog::setDoubleStep() diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp index 26a6245164..a5d627b075 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp @@ -620,11 +620,41 @@ void tst_QMessageBox::expandDetailsWithoutMoving() // QTBUG-32473 QCOMPARE(box.geometry().topLeft(), geom.topLeft()); } +class MessageBox : public QMessageBox +{ + Q_OBJECT +protected: + bool event(QEvent *e) override + { + if (e->type() == QEvent::Polish) { + const bool result = QMessageBox::event(e); + polished = true; + return result; + } + return QMessageBox::event(e); + } +public: + bool polished = false; +}; + void tst_QMessageBox::optionsEmptyByDefault() { QMessageBox b; QCOMPARE(b.options(), QMessageBox::Options()); QVERIFY(!b.testOption(QMessageBox::Option::DontUseNativeDialog)); + + { + MessageBox subclassed; + QCOMPARE(subclassed.options(), QMessageBox::Options()); + QTRY_VERIFY(subclassed.testOption(QMessageBox::Option::DontUseNativeDialog)); + } + { + MessageBox subclassed; + subclassed.setOption(QMessageBox::Option::DontUseNativeDialog, false); + QCOMPARE(subclassed.options(), QMessageBox::Options()); + QTRY_VERIFY(subclassed.polished); + QVERIFY(!subclassed.testOption(QMessageBox::Option::DontUseNativeDialog)); + } } void tst_QMessageBox::changeNativeOption() diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp index bf3d494265..8111e4a6f8 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/dialogs/qwizard/tst_qwizard.cpp @@ -1000,7 +1000,7 @@ void tst_QWizard::setOption_IgnoreSubTitles() wizard1.show(); wizard2.show(); - QVERIFY(QTest::qWaitForWindowExposed(&wizard2)); + QVERIFY(QTest::qWaitForWindowActive(&wizard2)); // Check that subtitles are shown when they should (i.e., // they're set and IgnoreSubTitles is off). @@ -1069,34 +1069,21 @@ void tst_QWizard::setOption_ExtendedWatermarkPixmap() QPixmap watermarkPixmap(200, 400); watermarkPixmap.fill(Qt::black); - QWizard wizard1; - wizard1.setButtonLayout(QList() << QWizard::CancelButton); - QVERIFY(!wizard1.testOption(QWizard::ExtendedWatermarkPixmap)); - QWizardPage *page11 = new QWizardPage; - page11->setTitle("Page X"); - page11->setPixmap(QWizard::WatermarkPixmap, watermarkPixmap); + QWizard wizard; + wizard.setButtonLayout(QList() << QWizard::CancelButton); + QVERIFY(!wizard.testOption(QWizard::ExtendedWatermarkPixmap)); + QWizardPage *page1 = new QWizardPage; + page1->setTitle("Page X"); + page1->setPixmap(QWizard::WatermarkPixmap, watermarkPixmap); - QWizardPage *page12 = new QWizardPage; - page12->setTitle("Page X"); + QWizardPage *page2 = new QWizardPage; + page2->setTitle("Page X"); - wizard1.addPage(page11); - wizard1.addPage(page12); + wizard.addPage(page1); + wizard.addPage(page2); - QWizard wizard2; - wizard2.setButtonLayout(QList() << QWizard::CancelButton); - wizard2.setOption(QWizard::ExtendedWatermarkPixmap, true); - QWizardPage *page21 = new QWizardPage; - page21->setTitle("Page X"); - page21->setPixmap(QWizard::WatermarkPixmap, watermarkPixmap); - - QWizardPage *page22 = new QWizardPage; - page22->setTitle("Page X"); - - wizard2.addPage(page21); - wizard2.addPage(page22); - - wizard1.show(); - wizard2.show(); + wizard.show(); + QVERIFY(QTest::qWaitForWindowExposed(&wizard)); // Check the impact of watermark pixmaps on the rest of the layout. @@ -1104,23 +1091,23 @@ void tst_QWizard::setOption_ExtendedWatermarkPixmap() QImage i1[2]; QImage i2[2]; for (int j = 0; j < 2; ++j) { - wizard1.setOption(QWizard::ExtendedWatermarkPixmap, j == 0); + wizard.setOption(QWizard::ExtendedWatermarkPixmap, j == 0); - wizard1.setWizardStyle(i == 0 ? QWizard::ClassicStyle + wizard.setWizardStyle(i == 0 ? QWizard::ClassicStyle : i == 1 ? QWizard::ModernStyle : QWizard::MacStyle); - wizard1.restart(); - wizard1.setMaximumSize(1000, 1000); - wizard1.resize(600, 600); - i1[j] = grabWidget(&wizard1); + wizard.restart(); + wizard.setMaximumSize(1000, 1000); + wizard.resize(600, 600); + i1[j] = grabWidget(&wizard); - wizard1.next(); - wizard1.setMaximumSize(1000, 1000); - wizard1.resize(600, 600); - i2[j] = grabWidget(&wizard1); + wizard.next(); + wizard.setMaximumSize(1000, 1000); + wizard.resize(600, 600); + i2[j] = grabWidget(&wizard); } - if (wizard1.wizardStyle() == QWizard::MacStyle) { + if (wizard.wizardStyle() == QWizard::MacStyle) { QCOMPARE(i1[0], i1[1]); QCOMPARE(i2[0], i2[1]); QCOMPARE(i1[0], i2[0]); @@ -2088,6 +2075,8 @@ void tst_QWizard::combinations() wizard.applyOperations(operations); wizard.show(); // ### TODO: Required, but why? Should wizard.createImage() care? + QVERIFY(QTest::qWaitForWindowExposed(&wizard)); + static QImage refImage; static QSize refMinSize; static QString refDescr; diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST index 8f8c065560..3d70a4d7b0 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST @@ -9,3 +9,5 @@ android android [windowOpacity] macos # QTBUG-139950 +[bypassGraphicsProxyWidget] +wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 3e5c65cf0b..10ebdccfa6 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -3283,7 +3283,10 @@ void tst_QAbstractItemView::inputMethodOpensEditor() tableWidget.setCurrentCell(editItem.y(), editItem.x()); const QString orgText = tableWidget.currentItem()->text(); const QModelIndex currentIndex = tableWidget.currentIndex(); - QCOMPARE(tableWidget.inputMethodQuery(Qt::ImCursorRectangle), tableWidget.visualRect(currentIndex)); + + QRect currentVisualRect = tableWidget.visualRect(currentIndex); + QRect currentRect(tableWidget.viewport()->mapTo(&tableWidget, currentVisualRect.topLeft()), currentVisualRect.size()); + QCOMPARE(tableWidget.inputMethodQuery(Qt::ImCursorRectangle).toRect(), currentRect); // simulate the start of input via a composing input method sendInputMethodEvent(preedit.left(1)); @@ -3296,7 +3299,10 @@ void tst_QAbstractItemView::inputMethodOpensEditor() // the item view delegates input method queries to the editor const QRect cursorRect = tableWidget.inputMethodQuery(Qt::ImCursorRectangle).toRect(); QVERIFY(cursorRect.isValid()); - QVERIFY(tableWidget.visualRect(currentIndex).intersects(cursorRect)); + + currentVisualRect = tableWidget.visualRect(currentIndex); + currentRect = QRect(tableWidget.viewport()->mapTo(&tableWidget, currentVisualRect.topLeft()), currentVisualRect.size()); + QVERIFY(currentRect.intersects(cursorRect)); // finish preediting, then commit or cancel the input sendInputMethodEvent(preedit); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp index 236cd6212f..ff8c62bf6a 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qlistview/tst_qlistview.cpp @@ -2997,6 +2997,7 @@ void tst_QListView::internalDragDropMove() // The test relies on the global position of mouse events; make sure // the window is properly mapped on X11. QVERIFY(QTest::qWaitForWindowActive(&list)); + QTRY_VERIFY(QApplication::topLevelAt(list.geometry().center())); QVERIFY(QTest::qWaitFor([&]() { return list.m_gotValidResizeEvent; })); // execute as soon as the eventloop is running again // which is the case inside list.startDrag() diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index 9dee14b7e4..b09c28af30 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -4275,7 +4275,7 @@ void tst_QTableView::mouseWheel_data() { QTest::addColumn("scrollMode"); QTest::addColumn("delta"); - QTest::addColumn("horizontalPositon"); + QTest::addColumn("horizontalPosition"); QTest::addColumn("verticalPosition"); QTest::newRow("scroll up per item") @@ -4293,7 +4293,7 @@ void tst_QTableView::mouseWheel() { QFETCH(QAbstractItemView::ScrollMode, scrollMode); QFETCH(int, delta); - QFETCH(int, horizontalPositon); + QFETCH(int, horizontalPosition); QFETCH(int, verticalPosition); QtTestTableModel model(100, 100); @@ -4322,7 +4322,7 @@ void tst_QTableView::mouseWheel() QWheelEvent horizontalEvent(pos, view.mapToGlobal(pos), QPoint(), QPoint(delta, 0), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); QApplication::sendEvent(view.viewport(), &horizontalEvent); - QVERIFY(qAbs(view.horizontalScrollBar()->value() - horizontalPositon) < 15); + QVERIFY(qAbs(view.horizontalScrollBar()->value() - horizontalPosition) < 15); QApplication::sendEvent(view.viewport(), &verticalEvent); QVERIFY(qAbs(view.verticalScrollBar()->value() - verticalPosition) < 15); } diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index 7c12e20b42..8a858ffa86 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -2439,6 +2439,7 @@ void tst_QTreeView::spanningItems() QtTestModel model(10, 10); model.onlyValidCalls = true; QTreeView view; + view.header()->setMinimumSectionSize(20); view.setModel(&model); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/BLACKLIST deleted file mode 100644 index 1f333884bd..0000000000 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -[exitFromEventLoop] -wayland - diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/test/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/test/BLACKLIST index 70dddbe0fa..ef8dfe80d0 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/test/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qapplication/test/BLACKLIST @@ -5,3 +5,5 @@ android [modalDialog] android +[exitFromEventLoop] +wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp index 255bcaa5be..48cb2c6288 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp @@ -237,6 +237,7 @@ void tst_QGestureRecognizer::pinchGesture() widget.setWindowTitle(QTest::currentTestFunction()); widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); + QTRY_VERIFY(QApplication::topLevelAt(widget.geometry().center())); QList points; points.append(widget.rect().center()); @@ -313,6 +314,7 @@ void tst_QGestureRecognizer::swipeGesture() widget.setWindowFlag(Qt::FramelessWindowHint); widget.show(); QVERIFY(QTest::qWaitForWindowExposed(&widget)); + QTRY_VERIFY(QApplication::topLevelAt(widget.geometry().center())); // Start a swipe sequence with 2 points (QTBUG-15768) const QPoint fingerDistance(m_fingerDistance, m_fingerDistance); @@ -403,6 +405,7 @@ void tst_QGestureRecognizer::touchReplay() QWindow* windowHandle = parent.window()->windowHandle(); const QPoint globalPos = QPoint(42, 16); + QTRY_VERIFY(QApplication::topLevelAt(parent.geometry().center())); QTest::touchEvent(windowHandle, m_touchDevice.get()).press(1, globalPos); QTest::touchEvent(windowHandle, m_touchDevice.get()).release(1, globalPos); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/BLACKLIST index 033f1f3b7e..1b7a292971 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/BLACKLIST @@ -55,7 +55,7 @@ wayland wayland [reparent] wayland -[mapsFromAndTo] +[mapFromAndTo] wayland [dumpObjectTree] wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 359a094647..45b9e90521 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -12583,6 +12583,7 @@ void tst_QWidget::synthMouseDoubleClick() widget.show(); QWindow* window = widget.windowHandle(); QVERIFY(QTest::qWaitForWindowExposed(window)); + QTRY_VERIFY(QApplication::topLevelAt(widget.geometry().center())); // tap once; move slightly from press to release QPoint p(20, 20); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp index e7d65db550..26e429a3d9 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/kernel/qwindowcontainer/tst_qwindowcontainer.cpp @@ -62,6 +62,7 @@ private slots: void testPlatformSurfaceEvent(); void embedWidgetWindow(); void testFocus(); + void testFocusMultipleContainers(); void parentDestroyed(); void cleanup(); @@ -531,6 +532,53 @@ void tst_QWindowContainer::testFocus() QVERIFY(!lineEdit->hasFocus()); } +void tst_QWindowContainer::testFocusMultipleContainers() +{ + class FocusCounter : public QObject { + public: + int count = 0; + + bool eventFilter(QObject *, QEvent *e) override { + if (e->type() == QEvent::FocusIn) { + ++count; + if (count >= 50) + return true; // eat the event to break the loop + } + return false; + } + }; + + auto *window1 = new QWindow; + auto *window2 = new QWindow; + QScopedPointer container1(QWidget::createWindowContainer(window1)); + container1->setWindowTitle("Primary Window"); + container1->resize(400, 300); + FocusCounter windowCounter1; + window1->installEventFilter(&windowCounter1); + + QScopedPointer container2(QWidget::createWindowContainer(window2)); + container2->setWindowTitle("Secondary Window"); + container2->resize(400, 300); + FocusCounter windowCounter2; + window2->installEventFilter(&windowCounter2); + + container1->move(m_availableGeometry.x() + 100, m_availableGeometry.y() + 100); + container2->move(m_availableGeometry.x() + 520, m_availableGeometry.y() + 100); + + container1->setFocusPolicy(Qt::StrongFocus); + container2->setFocusPolicy(Qt::StrongFocus); + container1->show(); + container2->show(); + QVERIFY(QTest::qWaitForWindowExposed(container1.data())); + QVERIFY(QTest::qWaitForWindowExposed(container2.data())); + // We can not reliably test the focus event count for + // each window as that is up to the window manager, but it + // should not be more than 1 + QTest::qWait(100); + QCOMPARE_LE(windowCounter1.count, 1); + QCOMPARE_LE(windowCounter2.count, 1); +} + class CreateDestroyWidget : public QWidget { public: diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp index 679595058e..7a58b0307a 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/styles/qstyle/tst_qstyle.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,7 @@ private slots: void testWindowsStyle(); #if defined(Q_OS_WIN) && !defined(QT_NO_STYLE_WINDOWSVISTA) void testWindowsVistaStyle(); + void testWindowsVistaMenuIconSize(); #endif #ifdef Q_OS_MAC void testMacStyle(); @@ -309,6 +311,42 @@ void tst_QStyle::testWindowsVistaStyle() QVERIFY(!vistastyle.isNull()); QVERIFY(testAllFunctions(vistastyle.data())); } + +class RecordingIconEngine : public QIconEngine +{ +public: + mutable QRect lastPaintRect; + + void paint(QPainter *, const QRect &rect, QIcon::Mode, QIcon::State) override + { + lastPaintRect = rect; + } + + QIconEngine *clone() const override { return new RecordingIconEngine(*this); } + QString iconName() override { return {}; } +}; + +void tst_QStyle::testWindowsVistaMenuIconSize() +{ + QScopedPointer style(QStyleFactory::create("WindowsVista")); + QVERIFY(!style.isNull()); + + QMenu menu; + menu.setStyle(style.data()); + + auto *engine = new RecordingIconEngine; + QIcon icon(engine); + menu.addAction(icon, "Test Action"); + + menu.show(); + QVERIFY(QTest::qWaitForWindowExposed(&menu)); + + const int expectedSize = style->pixelMetric(QStyle::PM_SmallIconSize, nullptr, &menu); + QVERIFY(expectedSize > 0); + QVERIFY(!engine->lastPaintRect.isNull()); + QCOMPARE(engine->lastPaintRect.width(), expectedSize); + QCOMPARE(engine->lastPaintRect.height(), expectedSize); +} #endif #ifdef Q_OS_MAC diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp index 00d0fdaf94..44c0d529ff 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qabstractspinbox/tst_qabstractspinbox.cpp @@ -127,9 +127,6 @@ void tst_QAbstractSpinBox::task228728_cssselector() void tst_QAbstractSpinBox::inputMethodUpdate() { - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); - QSpinBox box; box.setRange(0, 1); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp index 172e9fe7ac..08d6748153 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp @@ -84,9 +84,6 @@ void tst_QButtonGroup::arrowKeyNavigation() if (!qt_tab_all_widgets()) QSKIP("This test requires full keyboard control to be enabled."); - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); - QDialog dlg(0); QHBoxLayout layout(&dlg); QGroupBox g1("1", &dlg); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp index 2a65f19a45..d8c9763d70 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcalendarwidget/tst_qcalendarwidget.cpp @@ -138,9 +138,6 @@ void tst_QCalendarWidget::getSetCheck() void tst_QCalendarWidget::buttonClickCheck() { - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); - QCalendarWidget object; QSize size = object.sizeHint(); object.setGeometry(0,0,size.width(), size.height()); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/BLACKLIST b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/BLACKLIST index 2d6228075a..d6e40e0b53 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/BLACKLIST +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/BLACKLIST @@ -1,3 +1,14 @@ [task_QTBUG_56693_itemFontFromModel] # Counts draw calls, but we could have multiple expose events QTBUG-62080 osx +wayland +[popupWheelHandling] +wayland +[task190351_layout] +wayland +[task_QTBUG_49831_scrollerNotActivated] +wayland +[setCustomModelAndView] +wayland +[closePopupWithCheckableItems] +wayland diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp index 10a67daa02..8a839d5dc5 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp @@ -3893,9 +3893,6 @@ void tst_QComboBox::cancelClosesPopupNotDialog() if (QGuiApplication::platformName() == "offscreen") QSKIP("The offscreen platform plugin doesn't activate popups."); - if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) - QSKIP("QWindow::requestActivate() is not supported."); - QDialog dialog; QComboBox combobox; combobox.addItems({"A", "B", "C"}); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp index e0c63e5ced..ba5798f273 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qcommandlinkbutton/tst_qcommandlinkbutton.cpp @@ -89,8 +89,6 @@ void tst_QCommandLinkButton::initTestCase() testWidget->setObjectName("testWidget"); testWidget->resize( 200, 200 ); testWidget->show(); - if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) - QSKIP("Wayland: This fails. Figure out why."); QVERIFY(QTest::qWaitForWindowActive(testWidget)); connect( testWidget, SIGNAL(clicked()), this, SLOT(onClicked()) ); diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp index a40a57b80d..2bf2e65541 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp @@ -655,6 +655,7 @@ void tst_QDockWidget::visibilityChanged() QDockWidget dw; QSignalSpy spy(&dw, SIGNAL(visibilityChanged(bool))); + mw.setWindowFlag(Qt::FramelessWindowHint); mw.addDockWidget(Qt::LeftDockWidgetArea, &dw); mw.show(); @@ -917,7 +918,7 @@ void tst_QDockWidget::dockLocationChanged() QCOMPARE(dockLocation(&spy), Qt::TopDockWidgetArea); spy.clear(); - QByteArray ba = mw.saveState(); + const QByteArray &ba = mw.saveState(); mw.restoreState(ba); QCOMPARE(spy.size(), 1); QCOMPARE(dockLocation(&spy), Qt::TopDockWidgetArea); @@ -984,6 +985,8 @@ void tst_QDockWidget::restoreStateOfFloating() QMainWindow mw; QDockWidget *dock = createTestDock(mw); mw.addDockWidget(Qt::TopDockWidgetArea, dock); + mw.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mw)); QVERIFY(!dock->isFloating()); QByteArray ba = mw.saveState(); dock->setFloating(true); @@ -2084,6 +2087,48 @@ void tst_QDockWidget::saveAndRestore() isFloating2 = d2->isFloating(); } + // Test save / restore consistency (QTBUG-142797) + { + constexpr auto compare = [](const QList actual, std::initializer_list expected) { + const auto expectedSize = static_cast(expected.size()); + if (actual.size() != expectedSize) { + qCDebug(lcTestDockWidget) << "expected size:" << expectedSize << "actual size:" << actual.size(); + return false; + } + for (auto *widget : expected) { + if (!actual.contains(widget)) { + qCDebug(lcTestDockWidget) << "expected:" << expected << "actual:" << actual; + return false; + } + } + return true; + }; + + QPointer d1; + QPointer d2; + QPointer cent; + QMainWindow* mainWindow; + QList path1; + QList path2; + qCreateFloatingTabs(mainWindow, cent, d1, d2, path1, path2); + auto *d3 = new QDockWidget; + d3->setObjectName("D3"); + mainWindow->addDockWidget(Qt::LeftDockWidgetArea, d3); + d3->setFloating(true); + QTRY_VERIFY(d3->isFloating()); + QPointer groupWindow = mainWindow->findChild(); + QVERIFY(groupWindow); + QVERIFY(compare(groupWindow->dockWidgets(), {d1, d2})); + d3->close(); + QVERIFY(!d3->toggleViewAction()->isChecked()); + const auto &ba = mainWindow->saveState(); + mainWindow->restoreState(ba); + QTRY_VERIFY(!groupWindow); + groupWindow = mainWindow->findChild(); + QVERIFY(compare(groupWindow->dockWidgets(), {d1, d2})); + QVERIFY(!d3->toggleViewAction()->isChecked()); // d3 must still be closed after restore + } + // Create a mainwindow with a central widget and two dock widgets. // Assign different properties to each dock widgets. // Write properties to a byte array. @@ -2117,6 +2162,35 @@ void tst_QDockWidget::saveAndRestore() QCOMPARE(d2->isFloating(), isFloating2); } + // MainWindow is child of another toplevel window + { + QWidget topLevel; + auto *layout = new QVBoxLayout(&topLevel); + + auto *tabs = new QTabWidget(&topLevel); + layout->addWidget(tabs); + + // Tab 1: Save Settings button + auto *tab1 = new QWidget; + tabs->addTab(tab1, "Front"); + + // Tab 2: QMainWindow with a left dock widget + auto *tab2 = new QMainWindow; + auto *dock = new QDockWidget("Dock1", tab2); + dock->setObjectName("dock1"); + tab2->addDockWidget(Qt::LeftDockWidgetArea, dock); + tab2->setCentralWidget(new QWidget); + tabs->addTab(tab2, "Main"); + + topLevel.resize(400, 400); + topLevel.show(); + QVERIFY(QTest::qWaitForWindowExposed(&topLevel)); + tab2->restoreState(tab2->saveState()); + tabs->setCurrentIndex(1); + QTRY_VERIFY(dock->isVisible()); + QVERIFY(!dock->isFloating()); + } + // Create a new main window, central window and two dock widgets. QPointer d1; QPointer d2; diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp index 5766ffeb38..6560f908f9 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qdoublespinbox/tst_qdoublespinbox.cpp @@ -23,46 +23,22 @@ #include #include -#include - #include // for QSystemLocale class DoubleSpinBox : public QDoubleSpinBox { Q_OBJECT public: - DoubleSpinBox(QWidget *parent = nullptr) - : QDoubleSpinBox(parent) - { /*connect(this, SIGNAL(valueChanged(double)), this, SLOT(foo(double)));*/ } - QString textFromValue(double v) const override - { - return QDoubleSpinBox::textFromValue(v); - } - QValidator::State validate(QString &text, int &pos) const override - { - return QDoubleSpinBox::validate(text, pos); - } - double valueFromText(const QString &text) const override - { - return QDoubleSpinBox::valueFromText(text); - } -#if QT_CONFIG(wheelevent) - void wheelEvent(QWheelEvent *event) override - { - QDoubleSpinBox::wheelEvent(event); - } -#endif - void initStyleOption(QStyleOptionSpinBox *option) const override - { - QDoubleSpinBox::initStyleOption(option); - } + using QDoubleSpinBox::QDoubleSpinBox; - QLineEdit* lineEdit() const { return QDoubleSpinBox::lineEdit(); } -public slots: - void foo(double vla) - { - qDebug() << vla; - } + using QDoubleSpinBox::textFromValue; + using QDoubleSpinBox::validate; + using QDoubleSpinBox::valueFromText; + using QDoubleSpinBox::initStyleOption; + using QDoubleSpinBox::lineEdit; +#if QT_CONFIG(wheelevent) + using QDoubleSpinBox::wheelEvent; +#endif }; class PressAndHoldStyle : public QProxyStyle @@ -111,7 +87,6 @@ class tst_QDoubleSpinBox : public QObject Q_OBJECT public: tst_QDoubleSpinBox(); - virtual ~tst_QDoubleSpinBox(); public slots: void initTestCase(); void cleanup(); @@ -210,19 +185,14 @@ static QLatin1String modifierToName(Qt::KeyboardModifier modifier) switch (modifier) { case Qt::NoModifier: return QLatin1String("No"); - break; case Qt::ControlModifier: return QLatin1String("Ctrl"); - break; case Qt::ShiftModifier: return QLatin1String("Shift"); - break; case Qt::AltModifier: return QLatin1String("Alt"); - break; case Qt::MetaModifier: return QLatin1String("Meta"); - break; default: qFatal("Unexpected keyboard modifier"); return QLatin1String(); @@ -234,10 +204,6 @@ tst_QDoubleSpinBox::tst_QDoubleSpinBox() QLocale::setDefault(QLocale::c()); } -tst_QDoubleSpinBox::~tst_QDoubleSpinBox() -{ -} - void tst_QDoubleSpinBox::initTestCase() { if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) @@ -264,7 +230,7 @@ void tst_QDoubleSpinBox::setValue_data() void tst_QDoubleSpinBox::setValue() { QFETCH(double, val); - QDoubleSpinBox spin(0); + QDoubleSpinBox spin; spin.setRange(-DBL_MAX, DBL_MAX); spin.setValue(val); QCOMPARE(spin.value(), val); @@ -386,7 +352,7 @@ void tst_QDoubleSpinBox::setTracking() QFETCH(QStringList, texts); QFETCH(bool, tracking); - QDoubleSpinBox spin(0); + QDoubleSpinBox spin; spin.setKeyboardTracking(tracking); spin.setDecimals(decimals); spin.show(); @@ -493,7 +459,7 @@ void tst_QDoubleSpinBox::setWrapping() QFETCH(QTestEventList, keys); QFETCH(DoubleList, expected); - QDoubleSpinBox spin(0); + QDoubleSpinBox spin; spin.setMinimum(minimum); spin.setMaximum(maximum); spin.setValue(startValue); @@ -504,10 +470,7 @@ void tst_QDoubleSpinBox::setWrapping() keys.simulate(&spin); - QCOMPARE(actualValues.size(), expected.size()); - for (int i=0; i("show"); QTestEventList keys; - DoubleList values; + DoubleList values = { 11, 10, 11 }; keys.addKeyClick(Qt::Key_Up); keys.addKeyClick(Qt::Key_Down); keys.addKeyClick(Qt::Key_Up); - values << 11 << 10 << 11; QTest::newRow("data0") << 1.0 << 10.0 << keys << values << false; QTest::newRow("data1") << 1.0 << 10.0 << keys << values << true; keys.clear(); - values.clear(); keys.addKeyClick(Qt::Key_Up); keys.addKeyClick(Qt::Key_Down); keys.addKeyClick(Qt::Key_Up); - values << 12.5 << 10.0 << 12.5; + values = { 12.5, 10.0, 12.5 }; QTest::newRow("data2") << 2.5 << 10.0 << keys << values << false; QTest::newRow("data3") << 2.5 << 10.0 << keys << values << true; + + keys.clear(); + for (int i = 0; i < 10; ++i) + keys.addKeyClick(Qt::Key_Down); + values = { 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0 }; + QTest::newRow("data4 - rounding error") << 0.1 << 1.0 << keys << values << true; + + keys.clear(); + for (int i = 0; i < 25; ++i) + keys.addKeyClick(Qt::Key_Up); + values = { 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4.0, 4.1, 4.2, 4.3, 4.4, 4.5, + 4.6, 4.7, 4.8, 4.9, 5.0 }; + QTest::newRow("data5 - rounding error") << 0.1 << 2.5 << keys << values << true; } void tst_QDoubleSpinBox::setSingleStep() @@ -583,7 +558,7 @@ void tst_QDoubleSpinBox::setSingleStep() QFETCH(DoubleList, expected); QFETCH(bool, show); - QDoubleSpinBox spin(0); + QDoubleSpinBox spin; actualValues.clear(); spin.setSingleStep(singleStep); spin.setValue(startValue); @@ -593,10 +568,7 @@ void tst_QDoubleSpinBox::setSingleStep() QCOMPARE(actualValues.size(), 0); keys.simulate(&spin); - QCOMPARE(actualValues.size(), expected.size()); - for (int i=0; iisUndoAvailable()); } -class task224497_fltMax_DoubleSpinBox : public QDoubleSpinBox -{ -public: - QLineEdit * lineEdit () const { return QDoubleSpinBox::lineEdit(); } -}; - void tst_QDoubleSpinBox::task224497_fltMax() { - task224497_fltMax_DoubleSpinBox dspin; + DoubleSpinBox dspin; dspin.setMinimum(3); dspin.setMaximum(FLT_MAX); dspin.show(); @@ -1145,7 +1105,7 @@ void tst_QDoubleSpinBox::task255471_decimalsValidation() void tst_QDoubleSpinBox::taskQTBUG_5008_textFromValueAndValidate() { - class DecoratedSpinBox : public QDoubleSpinBox + class DecoratedSpinBox : public DoubleSpinBox { public: DecoratedSpinBox() @@ -1155,11 +1115,6 @@ void tst_QDoubleSpinBox::taskQTBUG_5008_textFromValueAndValidate() setValue(1000); } - QLineEdit *lineEdit() const - { - return QDoubleSpinBox::lineEdit(); - } - //we use the French delimiters here QString textFromValue (double value) const override { @@ -1212,7 +1167,7 @@ void tst_QDoubleSpinBox::setGroupSeparatorShown_data() QTest::newRow("data1") << QLocale::Swedish << QLocale::Sweden; QTest::newRow("data2") << QLocale::German << QLocale::Germany; QTest::newRow("data3") << QLocale::Georgian << QLocale::Georgia; - QTest::newRow("data3") << QLocale::Macedonian << QLocale::Macedonia; + QTest::newRow("data4") << QLocale::Macedonian << QLocale::Macedonia; } void tst_QDoubleSpinBox::setGroupSeparatorShown() @@ -1588,7 +1543,7 @@ void tst_QDoubleSpinBox::stepModifierKeys() QFETCH(QTestEventList, keys); QFETCH(double, expectedValue); - QDoubleSpinBox spin(0); + QDoubleSpinBox spin; spin.setValue(startValue); QScopedPointer style( diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp index 325e188091..f9f8fd516b 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "qlabel.h" #include @@ -87,6 +88,7 @@ private Q_SLOTS: void resourceProvider(); void mouseEventPropagation_data(); void mouseEventPropagation(); + void linkHoverLeave(); private: QLabel *testWidget; @@ -133,6 +135,9 @@ void tst_QLabel::cleanupTestCase() delete testWidget; testWidget = 0; delete test_box; + + const QPoint safeCursorPos = QGuiApplication::primaryScreen()->availableGeometry().bottomRight() - QPoint(40, 40); + QCursor::setPos(safeCursorPos); } void tst_QLabel::init() @@ -730,5 +735,48 @@ void tst_QLabel::mouseEventPropagation() QTRY_COMPARE(widget.released(), count); } +// Test that linkHovered is re-emitted when mouse leaves and re-enters +// the label over the same link (QTBUG-143965) +void tst_QLabel::linkHoverLeave() +{ + QLabel label; + label.setWindowTitle("Label"); + label.setText(QLatin1String("
    Click here to test link hover")); + label.setTextInteractionFlags(Qt::LinksAccessibleByMouse); + label.setAlignment(Qt::AlignCenter); + label.setMouseTracking(true); + label.resize(200, 100); + QHBoxLayout hbox(testWidget); + hbox.addWidget(&label); + testWidget->setLayout(&hbox); + + QSignalSpy spy(&label, &QLabel::linkHovered); + + testWidget->show(); + QVERIFY(QTest::qWaitForWindowExposed(&label)); + + // Step 1: Set mouse to an initial position + const QPoint initalMousePosition = testWidget->screen()->geometry().topLeft() + QPoint(5, 5); + QCursor::setPos(initalMousePosition); + + // Step 2: Move mouse over the link + const QPoint center = label.rect().center(); + QTest::mouseMove(&label, center); + if (!QTest::qWaitFor([&spy]{ return spy.count() == 1; })) + QSKIP("QPA plugin doesn't generate Enter/Leave events for simulated mouse move events."); + + QCOMPARE(spy.last().at(0).toString(), QLatin1String("test")); + + // Step 3: Move mouse out (trigger leave event) + QTest::mouseMove(&label, QPoint(-10, -10)); + QTRY_COMPARE(spy.count(), 2); + QCOMPARE(spy.last().at(0).toString(), QString()); + + // Step 4: Move mouse back over the center + QTest::mouseMove(&label, center); + QTRY_COMPARE(spy.count(), 3); + QCOMPARE(spy.last().at(0).toString(), QLatin1String("test")); +} + QTEST_MAIN(tst_QLabel) #include "tst_qlabel.moc" diff --git a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp index 09d3eb1e8d..c044fb4fc7 100644 --- a/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp +++ b/local/recipes/qt/qtbase/source/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp @@ -1688,9 +1688,11 @@ void AddDockWidget::apply(QMainWindow *mw) const mw->addDockWidget(a, dw); break; case SplitMode: + mw->addDockWidget(Qt::BottomDockWidgetArea, dw); mw->splitDockWidget(other, dw, o); break; case TabMode: + mw->addDockWidget(Qt::BottomDockWidgetArea, dw); mw->tabifyDockWidget(other, dw); break; } diff --git a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/text/qbytearray/tst_bench_qbytearray.cpp b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/text/qbytearray/tst_bench_qbytearray.cpp index a97cba7c50..8589240823 100644 --- a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/text/qbytearray/tst_bench_qbytearray.cpp +++ b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/text/qbytearray/tst_bench_qbytearray.cpp @@ -29,6 +29,15 @@ private slots: void latin1Uppercasing_category(); void latin1Uppercasing_bitcheck(); + void toUpper_data(); + void toUpper(); + void toLower_data() { toUpper_data(); } + void toLower(); + void toUpperThenLower_data() { toUpper_data(); } + void toUpperThenLower(); + void toLowerThenUpper_data() { toUpper_data(); } + void toLowerThenUpper(); + void toPercentEncoding_data(); void toPercentEncoding(); @@ -327,6 +336,66 @@ void tst_QByteArray::latin1Uppercasing_bitcheck() } } +void tst_QByteArray::toUpper_data() +{ + QTest::addColumn("shared"); + + QTest::addRow("shared") << true; + QTest::addRow("detached") << false; +} + +void tst_QByteArray::toUpper() +{ + QFETCH(const bool, shared); + + QByteArray in = sourcecode; + if (!shared) + in.detach(); + + QBENCHMARK { + [[maybe_unused]] auto r = in.toUpper(); + } +} + +void tst_QByteArray::toLower() +{ + QFETCH(const bool, shared); + + QByteArray in = sourcecode; + if (!shared) + in.detach(); + + QBENCHMARK { + [[maybe_unused]] auto r = in.toLower(); + } +} + +void tst_QByteArray::toUpperThenLower() +{ + QFETCH(const bool, shared); + + QByteArray in = sourcecode; + if (!shared) + in.detach(); + + QBENCHMARK { + [[maybe_unused]] auto r = in.toUpper().toLower(); + } +} + +void tst_QByteArray::toLowerThenUpper() +{ + QFETCH(const bool, shared); + + QByteArray in = sourcecode; + if (!shared) + in.detach(); + + QBENCHMARK { + [[maybe_unused]] auto r = in.toLower().toUpper(); + } +} + void tst_QByteArray::toPercentEncoding_data() { QTest::addColumn("plaintext"); diff --git a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qmap/tst_bench_qmap.cpp b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qmap/tst_bench_qmap.cpp index db3c4fc7a2..a03471e46a 100644 --- a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qmap/tst_bench_qmap.cpp +++ b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qmap/tst_bench_qmap.cpp @@ -37,6 +37,12 @@ private slots: void insertMap(); + void take_data(); + void take(); + + void detach_data(); + void detach(); + private: QStringList helloEachWorld(int count); }; @@ -299,6 +305,61 @@ void tst_QMap::insertMap() } } +void tst_QMap::take_data() +{ + QTest::addColumn("size"); + QTest::addColumn("key"); + + QTest::addRow("0 in {}") << 0 << 0; + QTest::addRow("0 in {0}") << 1 << 0; + QTest::addRow("1 in {0}") << 1 << 1; + QTest::addRow("0 in {0, 1}") << 2 << 0; + QTest::addRow("1 in {0, 1}") << 2 << 1; + QTest::addRow("2 in {0, 1}") << 2 << 2; + QTest::addRow("0 in {0...16}") << 17 << 0; + QTest::addRow("7 in {0...16}") << 17 << 7; + QTest::addRow("16 in {0...16}") << 17 << 16; + QTest::addRow("17 in {0...16}") << 17 << 17; + QTest::addRow("1024 in {0...2047}") << 2048 << 1024; +} + +void tst_QMap::take() +{ + QFETCH(const int, size); + QFETCH(const int, key); + + QMap map; + for (int i = 0; i < size; ++i) + map[i] = QString::number(i); + + QBENCHMARK { + auto copy = map; + [[maybe_unused]] const auto r = copy.take(key); + } +} + +void tst_QMap::detach_data() +{ + QTest::addColumn("size"); + + for (int sz : {0, 1, 2, 17, 2048}) + QTest::addRow("%d", sz) << sz; +} + +void tst_QMap::detach() +{ + QFETCH(const int, size); + + QMap map; + for (int i = 0; i < size; ++i) + map[i] = QString::number(i); + + QBENCHMARK { + auto copy = map; + copy.detach(); + } +} + QTEST_MAIN(tst_QMap) #include "tst_bench_qmap.moc" diff --git a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qset/tst_bench_qset.cpp b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qset/tst_bench_qset.cpp index e5ad33d661..10f4494fe9 100644 --- a/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qset/tst_bench_qset.cpp +++ b/local/recipes/qt/qtbase/source/tests/benchmarks/corelib/tools/qset/tst_bench_qset.cpp @@ -71,12 +71,12 @@ struct ComplexType int a; int b; int c; -}; -inline uint qHash(const ComplexType &key, uint seed = 0) -{ - return uint(key.a) ^ seed; -} + friend size_t qHash(const ComplexType &key, size_t seed = 0) noexcept + { + return size_t(key.a) ^ seed; + } +}; inline bool operator==(const ComplexType &lhs, const ComplexType &rhs) { diff --git a/local/recipes/qt/qtbase/source/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp b/local/recipes/qt/qtbase/source/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp index 0c93e6d2ec..b7b60af074 100644 --- a/local/recipes/qt/qtbase/source/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp +++ b/local/recipes/qt/qtbase/source/tests/benchmarks/gui/image/qpixmapcache/tst_qpixmapcache.cpp @@ -113,12 +113,12 @@ struct styleStruct { && str.complex == complex && str.palette == palette && str.width == width && str.height == height && str.key == key; } -}; -uint qHash(const styleStruct &myStruct) -{ - return qHash(myStruct.state); -} + friend size_t qHash(const styleStruct &myStruct, size_t seed = 0) noexcept + { + return qHash(myStruct.state, seed); + } +}; void tst_QPixmapCache::styleUseCaseComplexKey() { diff --git a/local/recipes/qt/qtbase/source/tests/manual/keyevents/main.cpp b/local/recipes/qt/qtbase/source/tests/manual/keyevents/main.cpp index 888b7f9d3f..03a0e0401e 100644 --- a/local/recipes/qt/qtbase/source/tests/manual/keyevents/main.cpp +++ b/local/recipes/qt/qtbase/source/tests/manual/keyevents/main.cpp @@ -239,6 +239,16 @@ public: enableAction->setCheckable(true); enableAction->setChecked(true); +#if defined(Q_OS_APPLE) + QMenu *optionsMenu = menuBar()->addMenu("Options"); + auto *dontSwapAction = optionsMenu->addAction("Don't swap Ctrl and Meta", this, [this]{ + auto *action = static_cast(sender()); + qGuiApp->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, action->isChecked()); + }); + dontSwapAction->setCheckable(true); + dontSwapAction->setChecked(false); +#endif + auto *toolBar = addToolBar("Tools"); toolBar->setMovable(false); toolBar->addWidget(new QLabel("Key sequence editor:")); diff --git a/local/recipes/qt/qtbase/source/tests/manual/wasm/eventloop/main_exec/main.cpp b/local/recipes/qt/qtbase/source/tests/manual/wasm/eventloop/main_exec/main.cpp index 17eccafe18..bf86e8a656 100644 --- a/local/recipes/qt/qtbase/source/tests/manual/wasm/eventloop/main_exec/main.cpp +++ b/local/recipes/qt/qtbase/source/tests/manual/wasm/eventloop/main_exec/main.cpp @@ -10,10 +10,10 @@ class ClickWindow: public QRasterWindow { public: ClickWindow() { - qDebug() << "ClickWindow constructor"; + qWarning() << "ClickWindow constructor"; } ~ClickWindow() { - qDebug() << "ClickWindow destructor"; + qWarning() << "ClickWindow destructor"; } void paintEvent(QPaintEvent *ev) override { @@ -30,27 +30,31 @@ public: int main(int argc, char **argv) { - qDebug() << "main(): Creating QGuiApplication object"; - QGuiApplication app(argc, argv); + for (int i = 0; i < 5; ++i) { + qDebug() << "main(): Creating QGuiApplication object"; + QGuiApplication app(argc, argv); - QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ - qDebug() << "QCoreApplication::aboutToQuit"; - }); + QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){ + qDebug() << "QCoreApplication::aboutToQuit"; + }); - ClickWindow window; - window.show(); + ClickWindow window; + window.show(); - qDebug() << "main(): calling exec()"; - app.exec(); + qDebug() << "main(): calling exec()"; + app.exec(); - // The exec() call above never returns; instead, a JavaScript exception - // is thrown such that control returns to the browser while preserving - // the C++ stack. + // If not using asyncify: + // + // The exec() call above never returns; instead, a JavaScript exception + // is thrown such that control returns to the browser while preserving + // the C++ stack. - // This means that the window object above is not destroyed, and that - // shutdown code after exec() does not run. + // This means that the window object above is not destroyed, and that + // shutdown code after exec() does not run. - qDebug() << "main(): after exit"; // <- will not be printed + qDebug() << "main(): after exit"; // <- will not be printed + } } // Global variables are created before main() as usual, but not destroyed @@ -61,7 +65,7 @@ public: qDebug() << "Global constructor"; } ~Global() { - qDebug() << "Global destructor"; // <- will not be printed + qWarning() << "Global destructor"; // <- will not be printed, without asyncify } }; Global global; diff --git a/local/recipes/qt/qtbase/source/util/sbom/cyclonedx/qt_cyclonedx_generator/qt_cyclonedx_generator.py b/local/recipes/qt/qtbase/source/util/sbom/cyclonedx/qt_cyclonedx_generator/qt_cyclonedx_generator.py index 3b04a47d71..d69b0db82f 100644 --- a/local/recipes/qt/qtbase/source/util/sbom/cyclonedx/qt_cyclonedx_generator/qt_cyclonedx_generator.py +++ b/local/recipes/qt/qtbase/source/util/sbom/cyclonedx/qt_cyclonedx_generator/qt_cyclonedx_generator.py @@ -55,10 +55,10 @@ def check_package_dependencies() -> None: missing_packages.append("tomli") if importlib.util.find_spec("cyclonedx") is None: - missing_packages.append("cyclonedx") + missing_packages.append("cyclonedx-python-lib") if importlib.util.find_spec("packageurl") is None: - missing_packages.append("packageurl") + missing_packages.append("packageurl-python") if missing_packages: log.error(f"Missing required dependencies: {', '.join(missing_packages)}") @@ -137,11 +137,19 @@ class LicenseDict(TypedDict): text: str +class RelationshipDict(TypedDict): + # Optional fields + relationship_from: str + relationship_type: str + relationship_to: str + relationship_comment: str + class RootComponentDict(TypedDict): name: str spdx_id: str # Optional fields (since TypedDict doesn't support NotRequired in Python 3.9) # We'll use .get() to access these safely + component_type: str version: str description: str download_location: str @@ -149,6 +157,7 @@ class RootComponentDict(TypedDict): supplier: str supplier_url: str serial_number_uuid: str + relationships: list[RelationshipDict] class ComponentDict(TypedDict): @@ -163,7 +172,7 @@ class ComponentDict(TypedDict): purl_list: list[str] cpe_list: list[str] properties: list[CyclonePropertyDict] - dependencies: list[str] + relationships: list[RelationshipDict] class BuildToolDict(TypedDict): @@ -455,15 +464,20 @@ def process_toml(toml_data: TomlDataDict, cydx_bom: Bom) -> None: root_component_object, ) + log.debug("Processing project relationships.") + handle_project_relationships( + cydx_bom, + toml_data, + components, + ) + # Creates the root component of the BOM. # The CycloneDX root component is mapped to the Qt spdx project package e.g. qtbase. def handle_root_component( cydx_bom: Bom, toml_data: TomlDataDict ) -> tuple[Component, Optional[OrganizationalEntity], str]: - root_components_args: dict[str, Any] = { - "type": ComponentType.FRAMEWORK, - } + root_components_args: dict[str, Any] = {} root_component = validate_required_field(toml_data, "root_component", "TOML data") error_context = "root_component" @@ -477,6 +491,10 @@ def handle_root_component( assign_optional_field(root_component, root_components_args, "version") assign_optional_field(root_component, root_components_args, "description") + root_components_args["type"] = get_component_type_for_str( + root_component.get("component_type", "framework") + ) + # Process optional fields with transformations assign_optional_field( root_component, @@ -685,20 +703,44 @@ def handle_component_dependencies( if component_id not in external_components_spdx_ids: cydx_bom.register_dependency(root_component_object, [component_object]) # pyright: ignore [reportAttributeAccessIssue, reportArgumentType] - # Register dependencies declared in the toml. - # CycloneDX does not support different dependency types, like SPDX does. - if dependencies := component_toml.get("dependencies"): - for dependency_spdx_id in dependencies: - if dependency_spdx_id not in components: - log.warning( - f"Component {component_id} has a dependency on unknown component {dependency_spdx_id}, skipping." - ) - continue - dep_component = components[dependency_spdx_id] - cydx_bom.register_dependency(component_object, [dep_component]) # pyright: ignore [reportAttributeAccessIssue, reportArgumentType] - log.debug( - f"Created dependency from '{component_id}' to '{dependency_spdx_id}'." + # Register relationships declared in the toml. + if relationships := component_toml.get("relationships"): + process_relationships(relationships, cydx_bom, components) + + +def handle_project_relationships( + cydx_bom: Bom, + toml_data: TomlDataDict, + components: dict[str, Component], +) -> None: + root_component_toml = validate_required_field(toml_data, "root_component", "TOML data") + if relationships := root_component_toml.get("relationships"): + process_relationships(relationships, cydx_bom, components) + + +# Creates dependencies between components based on the relationships declared in the toml data. +# CycloneDX does not support different relationship types, like SPDX does, so the relationship +# type is ignored. +def process_relationships(relationships: list[RelationshipDict], cydx_bom: Bom, components: dict[str, Component]) -> None: + for relationship in relationships: + from_spdx_id = relationship["relationship_from"] + to_spdx_id = relationship["relationship_to"] + relationship_type = relationship["relationship_type"] + if from_spdx_id not in components: + log.warning( + f"Component '{from_spdx_id}' in 'from' dependency is unknown, skipping." ) + continue + if to_spdx_id not in components: + log.warning( + f"Component {to_spdx_id} in 'from' dependency is unknown, skipping." + ) + continue + from_component = components[from_spdx_id] + to_component = components[to_spdx_id] + cydx_bom.register_dependency(from_component, + [to_component]) # pyright: ignore [reportAttributeAccessIssue, reportArgumentType] + log.debug(f"Created dependency from '{from_spdx_id}' to '{to_spdx_id}'. The relationship type '{relationship_type}' is currently discarded.") # Handles PURL and CPE entries for a component. diff --git a/local/recipes/qt/qtbase/source/util/unicode/main.cpp b/local/recipes/qt/qtbase/source/util/unicode/main.cpp index e1dc504a73..5c4e951d67 100644 --- a/local/recipes/qt/qtbase/source/util/unicode/main.cpp +++ b/local/recipes/qt/qtbase/source/util/unicode/main.cpp @@ -34,7 +34,7 @@ using namespace Qt::StringLiterals; #ifndef qPrintableView // expands to x.size(), x.data() for use with "%.*s" -# define qPrintableView(x) q26::saturate_cast((x).size()), (x).data() +# define qPrintableView(x) q26::saturating_cast((x).size()), (x).data() #endif namespace {