diff options
Diffstat (limited to 'src')
82 files changed, 1189 insertions, 8685 deletions
diff --git a/src/3rdparty/pcre2/qt_attribution.json b/src/3rdparty/pcre2/qt_attribution.json index ef29ad7d951..0468bca1b3e 100644 --- a/src/3rdparty/pcre2/qt_attribution.json +++ b/src/3rdparty/pcre2/qt_attribution.json @@ -30,7 +30,7 @@ "Homepage": "http://www.pcre.org/", "Version": "10.47", "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.bz2", - "PURL": "pkg:github/PCRE2Project/pcre2@$<VERSION>", + "PURL": "pkg:github/PCRE2Project/pcre2@pcre2-$<VERSION>", "CPE": "cpe:2.3:a:pcre:pcre2:$<VERSION>:*:*:*:*:*:*:*", "License": "BSD 2-clause \"Simplified\" License", "LicenseId": "BSD-2-Clause", diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 1147205b79f..380b571c3cf 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -638,6 +638,7 @@ qt_internal_extend_target(Core CONDITION WIN32 platform/windows/qcomptr_p.h platform/windows/qbstr_p.h platform/windows/qcomvariant_p.h + platform/windows/quniquehandle_types_windows.cpp platform/windows/quniquehandle_types_windows_p.h LIBRARIES advapi32 authz @@ -1028,7 +1029,7 @@ qt_internal_extend_target(Core qt_internal_extend_target(Core CONDITION - QT_FEATURE_timezone AND UNIX + QT_FEATURE_timezone AND UNIX AND NOT VXWORKS AND NOT ANDROID AND NOT APPLE AND NOT QT_FEATURE_timezone_tzdb SOURCES time/qtimezoneprivate_tz.cpp @@ -1037,7 +1038,7 @@ qt_internal_extend_target(Core qt_internal_extend_target(Core CONDITION QT_FEATURE_icu AND QT_FEATURE_timezone - AND NOT UNIX AND NOT QT_FEATURE_timezone_tzdb + AND (VXWORKS OR NOT UNIX) AND NOT QT_FEATURE_timezone_tzdb SOURCES time/qtimezoneprivate_icu.cpp ) diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index d951b85c147..edcfba0f6ce 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -1150,7 +1150,7 @@ qt_feature("timezone" PUBLIC SECTION "Utilities" LABEL "QTimeZone" PURPOSE "Provides support for time-zone handling." - CONDITION NOT WASM AND NOT VXWORKS + CONDITION NOT WASM ) qt_feature("timezone_locale" PRIVATE SECTION "Utilities" diff --git a/src/corelib/doc/images/javaiterators1.svg b/src/corelib/doc/images/javaiterators1.svg new file mode 100644 index 00000000000..468dbe5371c --- /dev/null +++ b/src/corelib/doc/images/javaiterators1.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="340" + height="110" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .line-style { stroke: red; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .fill-style { stroke: none; fill: red } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .line-style { stroke: red; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: red } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .line-style { stroke: red; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .fill-style { stroke: none; fill: red } +</style> + +<g transform="translate(10.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">A</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(90.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">B</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(170.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">C</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(250.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">D</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(330.5, 10.5)"> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +</svg> diff --git a/src/corelib/doc/images/javaiterators2.svg b/src/corelib/doc/images/javaiterators2.svg new file mode 100644 index 00000000000..df4c6b352a6 --- /dev/null +++ b/src/corelib/doc/images/javaiterators2.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="340" + height="130" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .line-style { stroke: red; fill: none } + svg .fill-style { stroke: none; fill: red } + svg .np-line-style { stroke: blue; fill: none } + svg .np-fill-style { stroke: none; fill: blue } + svg .text-style { font: 20px arial; fill: black } + svg .small-text-style { font: 12px monospace; fill: black } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .line-style { stroke: red; fill: none } + [data-theme="dark"] svg .fill-style { stroke: none; fill: red } + [data-theme="dark"] svg .np-line-style { stroke: #4080ff; fill: none; stroke-width: 1.5 } + [data-theme="dark"] svg .np-fill-style { stroke: none; fill: #4080ff } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .small-text-style { font: 12px monospace; fill: #f2f2f2 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .line-style { stroke: red; fill: none } + [data-theme="light"] svg .fill-style { stroke: none; fill: red } + [data-theme="light"] svg .np-line-style { stroke: blue; fill: none } + [data-theme="light"] svg .np-fill-style { stroke: none; fill: blue } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .small-text-style { font: 12px monospace; fill: black } +</style> + +<g transform="translate(10.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">A</text> +</g> + +<g transform="translate(90.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">B</text> +<path d="M 0,60 c 0,30 50,40 80,30" class="np-line-style" /> +<path d="M 0,60 l -2,14 l 11,-4 z" class="np-fill-style" /> +<text x="-15" y="110" class="small-text-style">previous()</text> +</g> + +<g transform="translate(170.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">C</text> +<path d="M 0,60 v 50" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<text x="30" y="110" class="small-text-style">next()</text> +</g> + +<g transform="translate(250.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">D</text> +<path d="M 0,60 c 0,30 -50,40 -80,30" class="np-line-style" /> +<path d="M 0,60 l 2,14 l -11,-4 z" class="np-fill-style" /> +</g> + +</svg> diff --git a/src/corelib/doc/src/java-style-iterators.qdoc b/src/corelib/doc/src/java-style-iterators.qdoc index 856005cb66c..a0e5c53d633 100644 --- a/src/corelib/doc/src/java-style-iterators.qdoc +++ b/src/corelib/doc/src/java-style-iterators.qdoc @@ -42,7 +42,7 @@ diagram below shows the valid iterator positions as red arrows for a list containing four items: - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's a typical loop for iterating through all the elements of a QList<QString> in order: @@ -70,7 +70,7 @@ \l{QListIterator::next()}{next()} and \l{QListIterator::previous()}{previous()} on an iterator: - \image javaiterators2.png + \image javaiterators2.png Iterating to the next and previous items The following table summarizes the QListIterator API: diff --git a/src/corelib/itemmodels/qrangemodel.cpp b/src/corelib/itemmodels/qrangemodel.cpp index 05e3a39e589..b0c6c46b125 100644 --- a/src/corelib/itemmodels/qrangemodel.cpp +++ b/src/corelib/itemmodels/qrangemodel.cpp @@ -20,6 +20,8 @@ public: private: std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl; + friend class QRangeModelImplBase; + mutable QHash<int, QByteArray> m_roleNames; }; @@ -28,6 +30,16 @@ QRangeModel::QRangeModel(QRangeModelImplBase *impl, QObject *parent) { } +QRangeModelImplBase *QRangeModelImplBase::getImplementation(QRangeModel *model) +{ + return model->d_func()->impl.get(); +} + +const QRangeModelImplBase *QRangeModelImplBase::getImplementation(const QRangeModel *model) +{ + return model->d_func()->impl.get(); +} + /*! \class QRangeModel \inmodule QtCore diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index f38dc88c0d9..c2f473542d7 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -842,6 +842,11 @@ namespace QRangeModelDetails { using protocol = wrapped_t<Protocol>; using row = typename range_traits<wrapped_t<Range>>::value_type; + static constexpr bool is_tree = std::conjunction_v<protocol_parentRow<protocol, row>, + protocol_childRows<protocol, row>>; + static constexpr bool is_list = static_size_v<row> == 0 + && (!has_metaobject_v<row> || row_category<row>::isMultiRole); + static constexpr bool is_table = !is_list && !is_tree; static constexpr bool has_newRow = protocol_newRow<protocol>(); static constexpr bool has_deleteRow = protocol_deleteRow<protocol, row>(); @@ -1046,6 +1051,9 @@ public: typename C::MultiData >; + static Q_CORE_EXPORT QRangeModelImplBase *getImplementation(QRangeModel *model); + static Q_CORE_EXPORT const QRangeModelImplBase *getImplementation(const QRangeModel *model); + private: friend class QRangeModelPrivate; QRangeModel *m_rangeModel; @@ -1147,13 +1155,6 @@ protected: } } - static constexpr bool isMutable() - { - return range_features::is_mutable && row_features::is_mutable - && std::is_reference_v<row_reference> - && Structure::is_mutable_impl; - } - static constexpr int static_row_count = QRangeModelDetails::static_size_v<range_type>; static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>; static constexpr bool rows_are_owning_or_raw_pointers = @@ -1161,9 +1162,6 @@ protected: static constexpr int static_column_count = QRangeModelDetails::static_size_v<row_type>; static constexpr bool one_dimensional_range = static_column_count == 0; - static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; } - static constexpr bool dynamicColumns() { return static_column_count < 0; } - // A row might be a value (or range of values), or a pointer. // row_ptr is always a pointer, and const_row_ptr is a pointer to const. using row_ptr = wrapped_row_type *; @@ -1205,6 +1203,15 @@ protected: "The range holding a move-only row-type must support insert(pos, start, end)"); public: + static constexpr bool isMutable() + { + return range_features::is_mutable && row_features::is_mutable + && std::is_reference_v<row_reference> + && Structure::is_mutable_impl; + } + static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; } + static constexpr bool dynamicColumns() { return static_column_count < 0; } + explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel) : Ancestor(itemModel) , ProtocolStorage{std::forward<Protocol>(protocol)} @@ -1236,7 +1243,7 @@ public: if (row == index.row() && column == index.column()) return index; - if (column < 0 || column >= this->itemModel().columnCount()) + if (column < 0 || column >= this->columnCount({})) return {}; if (row == index.row()) @@ -1974,8 +1981,8 @@ public: } if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0 - || sourceRow < 0 || sourceRow + count - 1 >= this->itemModel().rowCount(sourceParent) - || destRow < 0 || destRow > this->itemModel().rowCount(destParent)) { + || sourceRow < 0 || sourceRow + count - 1 >= this->rowCount(sourceParent) + || destRow < 0 || destRow > this->rowCount(destParent)) { return false; } @@ -1995,11 +2002,14 @@ public: } } - QModelIndex parent(const QModelIndex &child) const { return that().parent(child); } + const protocol_type& protocol() const { return QRangeModelDetails::refTo(ProtocolStorage::object()); } + protocol_type& protocol() { return QRangeModelDetails::refTo(ProtocolStorage::object()); } + + QModelIndex parent(const QModelIndex &child) const { return that().parentImpl(child); } - int rowCount(const QModelIndex &parent) const { return that().rowCount(parent); } + int rowCount(const QModelIndex &parent) const { return that().rowCountImpl(parent); } - int columnCount(const QModelIndex &parent) const { return that().columnCount(parent); } + int columnCount(const QModelIndex &parent) const { return that().columnCountImpl(parent); } void destroy() { delete std::addressof(that()); } @@ -2035,6 +2045,11 @@ public: protected: ~QRangeModelImpl() { + deleteOwnedRows(); + } + + void deleteOwnedRows() + { // We delete row objects if we are not operating on a reference or pointer // to a range, as in that case, the owner of the referenced/pointed to // range also owns the row entries. @@ -2335,9 +2350,6 @@ protected: } - const protocol_type& protocol() const { return QRangeModelDetails::refTo(ProtocolStorage::object()); } - protocol_type& protocol() { return QRangeModelDetails::refTo(ProtocolStorage::object()); } - ModelData m_data; }; @@ -2385,7 +2397,7 @@ protected: return this->createIndex(row, column, QRangeModelDetails::pointerTo(*it)); } - QModelIndex parent(const QModelIndex &child) const + QModelIndex parentImpl(const QModelIndex &child) const { if (!child.isValid()) return {}; @@ -2410,12 +2422,12 @@ protected: return {}; } - int rowCount(const QModelIndex &parent) const + int rowCountImpl(const QModelIndex &parent) const { return Base::size(this->childRange(parent)); } - int columnCount(const QModelIndex &) const + int columnCountImpl(const QModelIndex &) const { // all levels of a tree have to have the same, static, column count if constexpr (Base::one_dimensional_range) @@ -2662,6 +2674,9 @@ class QGenericTableItemModelImpl using Base = QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>; friend class QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>; + static constexpr bool is_mutable_impl = true; + +public: using range_type = typename Base::range_type; using range_features = typename Base::range_features; using row_type = typename Base::row_type; @@ -2669,9 +2684,6 @@ class QGenericTableItemModelImpl using row_traits = typename Base::row_traits; using row_features = typename Base::row_features; - static constexpr bool is_mutable_impl = true; - -public: explicit QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel) : Base(std::forward<Range>(model), {}, itemModel) {} @@ -2692,19 +2704,19 @@ protected: } } - QModelIndex parent(const QModelIndex &) const + QModelIndex parentImpl(const QModelIndex &) const { return {}; } - int rowCount(const QModelIndex &parent) const + int rowCountImpl(const QModelIndex &parent) const { if (parent.isValid()) return 0; return int(Base::size(*this->m_data.model())); } - int columnCount(const QModelIndex &parent) const + int columnCountImpl(const QModelIndex &parent) const { if (parent.isValid()) return 0; @@ -2760,7 +2772,7 @@ protected: // dynamically sized rows all have to have the same column count if constexpr (Base::dynamicColumns() && row_features::has_resize) { if (QRangeModelDetails::isValid(empty_row)) - QRangeModelDetails::refTo(empty_row).resize(this->itemModel().columnCount()); + QRangeModelDetails::refTo(empty_row).resize(this->columnCount({})); } return empty_row; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 8366787ea66..57089f164b2 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2974,4 +2974,156 @@ const QVariant *QVariantConstPointer::operator->() const implement operator->(). */ +/*! + \class QVariant::ConstReference + \since 6.11 + \inmodule QtCore + \brief The QVariant::ConstReference acts as a const reference to a QVariant. + + As the generic iterators don't actually instantiate a QVariant on each + step, they cannot return a reference to one from operator*(). + QVariant::ConstReference provides the same functionality as an actual + reference to a QVariant would, but is backed a referred-to value given as + template parameter. The template is implemented for + QMetaSequence::ConstIterator, QMetaSequence::Iterator, + QMetaAssociation::ConstIterator, and QMetaAssociation::Iterator. +*/ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::ConstReference(const Referred &referred) + + Creates a QVariant::ConstReference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::ConstReference(Referred &&referred) + + Creates a QVariant::ConstReference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::operator QVariant() const + + Dereferences the reference to a QVariant. + This method needs to be specialized for each Referred type. It is + pre-defined for QMetaSequence::ConstIterator, QMetaSequence::Iterator, + QMetaAssociation::ConstIterator, and QMetaAssociation::Iterator. + */ + + +/*! + \class QVariant::Reference + \since 6.11 + \inmodule QtCore + \brief The QVariant::Reference acts as a non-const reference to a QVariant. + + As the generic iterators don't actually instantiate a QVariant on each + step, they cannot return a reference to one from operator*(). + QVariant::Reference provides the same functionality as an actual reference + to a QVariant would, but is backed a referred-to value given as template + parameter. The template is implemented for QMetaSequence::Iterator and + QMetaAssociation::Iterator. +*/ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::Reference(const Referred &referred) + + Creates a QVariant::Reference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::Reference(Referred &&referred) + + Creates a QVariant::Reference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(const Reference<Referred> &value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(Reference<Referred> &&value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. +*/ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(const QVariant &value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. + This method needs to be specialized for each Referred type. It is + pre-defined for QMetaSequence::Iterator and QMetaAssociation::Iterator. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::operator QVariant() const + + Dereferences the reference to a QVariant. By default this instantiates a + temporary QVariant::ConstReference and calls dereferences that. In cases + where instantiating a temporary ConstReference is expensive, this method + should be specialized. + */ + +/*! + \class QVariant::ConstPointer + \since 6.11 + \inmodule QtCore + \brief QVariant::ConstPointer is a template class that emulates a const pointer to QVariant. + + QVariant::ConstPointer wraps pointed-to value and returns a + QVariant::ConstReference to it from its operator*(). This makes it suitable + as replacement for an actual pointer. We cannot return an actual pointer + from generic iterators as the iterators don't hold an actual QVariant. +*/ + +/*! + \fn template<typename Pointed> QVariant::ConstPointer<Pointed>::ConstPointer(const Pointed &pointed) + + Constructs a QVariant::ConstPointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::ConstPointer<Pointed>::ConstPointer(Pointed &&pointed) + + Constructs a QVariant::ConstPointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::ConstReference<Pointer> QVariant::ConstPointer<Pointed>::operator*() const + + Dereferences the QVariant::ConstPointer to a QVariant::ConstReference. + */ + +/*! + \class QVariant::Pointer + \since 6.11 + \inmodule QtCore + \brief QVariant::Pointer is a template class that emulates a non-const pointer to QVariant. + + QVariant::Pointer wraps pointed-to value and returns a QVariant::Reference + to it from its operator*(). This makes it suitable as replacement for an + actual pointer. We cannot return an actual pointer from generic iterators as + the iterators don't hold an actual QVariant. +*/ + +/*! + \fn template<typename Pointed> QVariant::Pointer<Pointed>::Pointer(const Pointed &pointed) + + Constructs a QVariant::Pointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::Pointer<Pointed>::Pointer(Pointed &&pointed) + + Constructs a QVariant::Pointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::Reference<Pointer> QVariant::Pointer<Pointed>::operator*() const + + Dereferences the QVariant::Pointer to a QVariant::Reference. + */ + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 542b1d9b709..9b219d089b5 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -61,7 +61,20 @@ inline T qvariant_cast(const QVariant &); namespace QtPrivate { template<> constexpr inline bool qIsRelocatable<QVariant> = true; -} + +template<typename Referred> +class ConstReference; + +template<typename Referred> +class Reference; + +template<typename Pointed> +class ConstPointer; + +template<typename Pointed> +class Pointer; +} // namespace QtPrivate + class Q_CORE_EXPORT QVariant { template <typename T, typename... Args> @@ -228,6 +241,123 @@ private: >; public: + template<typename Referred> + class ConstReference + { + private: + const Referred m_referred; + + public: + // You can initialize a const reference from another one, but you can't assign to it. + + explicit ConstReference(const Referred &referred) + noexcept(std::is_nothrow_copy_constructible_v<Referred>) + : m_referred(referred) {} + explicit ConstReference(Referred &&referred) + noexcept(std::is_nothrow_move_constructible_v<Referred>) + : m_referred(std::move(referred)) {} + ConstReference(const ConstReference &) = default; + ConstReference(ConstReference &&) = default; + ~ConstReference() = default; + ConstReference &operator=(const ConstReference &value) = delete; + ConstReference &operator=(ConstReference &&value) = delete; + + // To be specialized for each Referred + operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant); + }; + + template<typename Referred> + class Reference + { + private: + Referred m_referred; + + friend void swap(Reference a, Reference b) { return a.swap(std::move(b)); } + + public: + // Assigning and initializing are different operations for references. + + explicit Reference(const Referred &referred) + noexcept(std::is_nothrow_copy_constructible_v<Referred>) + : m_referred(referred) {} + explicit Reference(Referred &&referred) + noexcept(std::is_nothrow_move_constructible_v<Referred>) + : m_referred(std::move(referred)) {} + Reference(const Reference &) = default; + Reference(Reference &&) = default; + ~Reference() = default; + + Reference &operator=(const Reference &value) + noexcept(Referred::canNoexceptAssignQVariant) + { + return operator=(QVariant(value)); + } + + Reference &operator=(Reference &&value) + noexcept(Referred::canNoexceptAssignQVariant) + { + return operator=(QVariant(value)); + } + + operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant) + { + return ConstReference(m_referred); + } + + void swap(Reference b) + { + // swapping a reference is not swapping the referred item, but swapping its contents. + QVariant tmp = *this; + *this = std::move(b); + b = std::move(tmp); + } + + // To be specialized for each Referred + Reference &operator=(const QVariant &value) noexcept(Referred::canNoexceptAssignQVariant); + }; + + template<typename Pointed> + class ConstPointer + { + private: + Pointed m_pointed; + + public: + explicit ConstPointer(const Pointed &pointed) + noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + : m_pointed(pointed) {} + explicit ConstPointer(Pointed &&pointed) + noexcept(std::is_nothrow_move_constructible_v<Pointed>) + : m_pointed(std::move(pointed)) {} + + ConstReference<Pointed> operator*() + const noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + { + return ConstReference<Pointed>(m_pointed); + } + }; + + template<typename Pointed> + class Pointer + { + private: + Pointed m_pointed; + + public: + explicit Pointer(const Pointed &pointed) + noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + : m_pointed(pointed) {} + explicit Pointer(Pointed &&pointed) + noexcept(std::is_nothrow_move_constructible_v<Pointed>) + : m_pointed(std::move(pointed)) {} + + Reference<Pointed> operator*() + const noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + { + return Reference<Pointed>(m_pointed); + } + }; + template <typename T, typename... Args, if_constructible<T, Args...> = true> explicit QVariant(std::in_place_type_t<T>, Args&&... args) diff --git a/src/corelib/platform/windows/quniquehandle_types_windows.cpp b/src/corelib/platform/windows/quniquehandle_types_windows.cpp new file mode 100644 index 00000000000..801c9ab13d6 --- /dev/null +++ b/src/corelib/platform/windows/quniquehandle_types_windows.cpp @@ -0,0 +1,17 @@ +// 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 + +#include "quniquehandle_types_windows_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtUniqueHandleTraits { + +bool HDCTraits::close(Type handle, HWND hwnd) noexcept +{ + return ::ReleaseDC(hwnd, handle); +} + +} // namespace QtUniqueHandleTraits + +QT_END_NAMESPACE diff --git a/src/corelib/platform/windows/quniquehandle_types_windows_p.h b/src/corelib/platform/windows/quniquehandle_types_windows_p.h new file mode 100644 index 00000000000..0b832d2b9d1 --- /dev/null +++ b/src/corelib/platform/windows/quniquehandle_types_windows_p.h @@ -0,0 +1,65 @@ +// 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 + +#ifndef QUNIQUEHANDLE_TYPES_WINDOWS_P_H +#define QUNIQUEHANDLE_TYPES_WINDOWS_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. +// + +#if defined(Q_OS_WIN) || defined(Q_QDOC) + +#include <QtCore/qnamespace.h> +#include <QtCore/qt_windows.h> +#include <QtCore/private/quniquehandle_p.h> + +QT_BEGIN_NAMESPACE + +namespace QtUniqueHandleTraits { + +struct HDCTraits +{ + using Type = HDC; + static Type invalidValue() noexcept { return nullptr; } + Q_CORE_EXPORT static bool close(Type handle, HWND hwnd) noexcept; +}; + +struct HDCDeleter +{ + using Type = HDCTraits::Type; + + constexpr HDCDeleter() noexcept = default; + explicit constexpr HDCDeleter(HWND hwnd) noexcept + : hwnd(hwnd) + {} + + void operator()(Type handle) const noexcept + { + if (handle != HDCTraits::invalidValue()) { + const bool success = HDCTraits::close(handle, hwnd); + Q_ASSERT(success); + } + } + + HWND hwnd{ nullptr }; +}; + +} // namespace QtUniqueHandleTraits +using QUniqueHDCHandle = QUniqueHandle< + QtUniqueHandleTraits::HDCTraits, + QtUniqueHandleTraits::HDCDeleter +>; + +QT_END_NAMESPACE + +#endif // Q_OS_WIN + +#endif // QUNIQUEHANDLE_TYPES_WINDOWS_P_H diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 711b70ebf8f..c01c1a9999d 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -3681,95 +3681,24 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) \sa remove() */ - -/*! \internal - Instead of detaching, or reallocating if "before" is shorter than "after" - and there isn't enough capacity, create a new string, copy characters to it - as needed, then swap it with "str". -*/ -static void replace_with_copy(QString &str, QSpan<size_t> indices, qsizetype blen, - QStringView after) -{ - const qsizetype alen = after.size(); - const char16_t *after_b = after.utf16(); - - const QString::DataPointer &str_d = str.data_ptr(); - auto src_start = str_d.begin(); - const qsizetype newSize = str_d.size + indices.size() * (alen - blen); - QString copy{ newSize, Qt::Uninitialized }; - QString::DataPointer ©_d = copy.data_ptr(); - auto dst = copy_d.begin(); - for (size_t index : indices) { - auto hit = str_d.begin() + index; - dst = std::copy(src_start, hit, dst); - dst = std::copy_n(after_b, alen, dst); - src_start = hit + blen; - } - dst = std::copy(src_start, str_d.end(), dst); - str.swap(copy); -} - -// No detaching or reallocation is needed -static void replace_in_place(QString &str, QSpan<size_t> indices, - qsizetype blen, QStringView after) -{ - const qsizetype alen = after.size(); - const char16_t *after_b = after.utf16(); - const char16_t *after_e = after.utf16() + after.size(); - - if (blen == alen) { // Replace in place - for (size_t index : indices) - std::copy_n(after_b, alen, str.data_ptr().begin() + index); - } else if (blen > alen) { // Replace from front - char16_t *begin = str.data_ptr().begin(); - char16_t *hit = begin + indices.front(); - char16_t *to = hit; - to = std::copy_n(after_b, alen, to); - char16_t *movestart = hit + blen; - for (size_t index : indices.sliced(1)) { - hit = begin + index; - to = std::move(movestart, hit, to); - to = std::copy_n(after_b, alen, to); - movestart = hit + blen; - } - to = std::move(movestart, str.data_ptr().end(), to); - str.resize(std::distance(begin, to)); - } else { // blen < alen, Replace from back - const qsizetype oldSize = str.data_ptr().size; - const qsizetype adjust = indices.size() * (alen - blen); - const qsizetype newSize = oldSize + adjust; - - str.resize(newSize); - char16_t *begin = str.data_ptr().begin(); - char16_t *moveend = begin + oldSize; - char16_t *to = str.data_ptr().end(); - - for (auto it = indices.rbegin(), end = indices.rend(); it != end; ++it) { - char16_t *hit = begin + *it; - char16_t *movestart = hit + blen; - to = std::move_backward(movestart, moveend, to); - to = std::copy_backward(after_b, after_e, to); - moveend = hit; - } - } -} - -static void replace_helper(QString &str, QSpan<size_t> indices, qsizetype blen, QStringView after) +static void replace_helper(QString &str, QSpan<qsizetype> indices, qsizetype blen, QStringView after) { const qsizetype oldSize = str.data_ptr().size; const qsizetype adjust = indices.size() * (after.size() - blen); const qsizetype newSize = oldSize + adjust; + using A = QStringAlgorithms<QString>; if (str.data_ptr().needsDetach() || needsReallocate(str, newSize)) { - replace_with_copy(str, indices, blen, after); + A::replace_helper(str, blen, after, indices); return; } - if (QtPrivate::q_points_into_range(after.begin(), str)) + if (QtPrivate::q_points_into_range(after.begin(), str)) { // Copy after if it lies inside our own d.b area (which we could // possibly invalidate via a realloc or modify by replacement) - replace_in_place(str, indices, blen, QVarLengthArray(after.begin(), after.end())); - else - replace_in_place(str, indices, blen, after); + A::replace_helper(str, blen, QVarLengthArray(after.begin(), after.end()), indices); + } else { + A::replace_helper(str, blen, after, indices); + } } /*! @@ -3811,8 +3740,8 @@ QString &QString::replace(qsizetype pos, qsizetype len, const QChar *after, qsiz if (len > this->size() - pos) len = this->size() - pos; - size_t index = pos; - replace_helper(*this, QSpan(&index, 1), len, QStringView{after, alen}); + qsizetype indices[] = {pos}; + replace_helper(*this, indices, len, QStringView{after, alen}); return *this; } @@ -3890,7 +3819,7 @@ QString &QString::replace(const QChar *before, qsizetype blen, qsizetype index = 0; - QVarLengthArray<size_t> indices; + QVarLengthArray<qsizetype> indices; while ((index = matcher.indexIn(*this, index)) != -1) { indices.push_back(index); if (blen) // Step over before: @@ -3925,7 +3854,7 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs const char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode()); - QVarLengthArray<size_t> indices; + QVarLengthArray<qsizetype> indices; if (cs == Qt::CaseSensitive) { const char16_t *begin = d.begin(); const char16_t *end = d.end(); diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index bb70678a958..6e4e532fd7d 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -172,27 +172,15 @@ inline Qt::HANDLE QThread::currentThreadId() noexcept #elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86_64 Linux, BSD uses FS __asm__("mov %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : ); -#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN) +#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN) && defined(Q_CC_MSVC) // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block - // First get the pointer to the TIB - quint8 *tib; -# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics - __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :); -# else - tib = reinterpret_cast<quint8 *>(__readgsqword(0x30)); -# endif - // Then read the thread ID - tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48); -#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN) - // First get the pointer to the TIB - quint8 *tib; -# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics - __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :); -# else - tib = reinterpret_cast<quint8 *>(__readfsdword(0x18)); -# endif - // Then read the thread ID - tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24); + tid = reinterpret_cast<Qt::HANDLE>(__readgsqword(0x48)); +#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN) // !Q_CC_MSVC + __asm__("mov %%gs:0x48, %0" : "=r" (tid)); +#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN) && defined(Q_CC_MSVC) + tid = reinterpret_cast<Qt::HANDLE>(__readfsdword(0x24)); +#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN) // !Q_CC_MSVC + __asm__("mov %%fs:0x24, %0" : "=r" (tid)); #else #undef QT_HAS_FAST_CURRENT_THREAD_ID tid = currentThreadIdImpl(); diff --git a/src/corelib/time/qgregoriancalendar.cpp b/src/corelib/time/qgregoriancalendar.cpp index d46d24ac30d..dfb99c5073d 100644 --- a/src/corelib/time/qgregoriancalendar.cpp +++ b/src/corelib/time/qgregoriancalendar.cpp @@ -31,6 +31,7 @@ static_assert(qDivMod<86400>(-172800).remainder == 0); /*! \since 5.14 + \internal \class QGregorianCalendar \inmodule QtCore diff --git a/src/corelib/time/qjalalicalendar.cpp b/src/corelib/time/qjalalicalendar.cpp index 8bc9fe125e7..683ce6e7712 100644 --- a/src/corelib/time/qjalalicalendar.cpp +++ b/src/corelib/time/qjalalicalendar.cpp @@ -39,6 +39,7 @@ qint64 firstDayOfYear(int year, int cycleNo) /*! \since 5.14 + \internal \class QJalaliCalendar \inmodule QtCore diff --git a/src/corelib/time/qjuliancalendar.cpp b/src/corelib/time/qjuliancalendar.cpp index 47da952b84a..cf3718f471d 100644 --- a/src/corelib/time/qjuliancalendar.cpp +++ b/src/corelib/time/qjuliancalendar.cpp @@ -13,6 +13,7 @@ using namespace QRoundingDown; /*! \since 5.14 + \internal \class QJulianCalendar \inmodule QtCore diff --git a/src/corelib/time/qmilankoviccalendar.cpp b/src/corelib/time/qmilankoviccalendar.cpp index a3ffa2a3053..14aef83afe3 100644 --- a/src/corelib/time/qmilankoviccalendar.cpp +++ b/src/corelib/time/qmilankoviccalendar.cpp @@ -13,6 +13,7 @@ using namespace QRoundingDown; /*! \since 5.14 + \internal \class QMilankovicCalendar \inmodule QtCore diff --git a/src/corelib/time/qromancalendar.cpp b/src/corelib/time/qromancalendar.cpp index ae113cf8323..a8ce027275a 100644 --- a/src/corelib/time/qromancalendar.cpp +++ b/src/corelib/time/qromancalendar.cpp @@ -9,6 +9,7 @@ QT_BEGIN_NAMESPACE /*! \since 5.14 + \internal \class QRomanCalendar \inmodule QtCore diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index f44c681ea80..7b43aab22d1 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -29,7 +29,7 @@ static QTimeZonePrivate *newBackendTimeZone() return new QMacTimeZonePrivate(); #elif defined(Q_OS_ANDROID) return new QAndroidTimeZonePrivate(); -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) return new QTzTimeZonePrivate(); #elif QT_CONFIG(icu) return new QIcuTimeZonePrivate(); @@ -50,7 +50,7 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId) return new QMacTimeZonePrivate(ianaId); #elif defined(Q_OS_ANDROID) return new QAndroidTimeZonePrivate(ianaId); -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) return new QTzTimeZonePrivate(ianaId); #elif QT_CONFIG(icu) return new QIcuTimeZonePrivate(ianaId); @@ -1482,7 +1482,8 @@ QTimeZone QTimeZone::utc() bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId) { -#if defined(Q_OS_UNIX) && !(defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)) +#if defined(Q_OS_UNIX) && !(QT_CONFIG(timezone_tzdb) || defined(Q_OS_DARWIN) \ + || defined(Q_OS_ANDROID) || defined(Q_OS_VXWORKS)) // Keep #if-ery consistent with selection of QTzTimeZonePrivate in // newBackendTimeZone(). Skip the pre-check, as the TZ backend accepts POSIX // zone IDs, which need not be valid IANA IDs. See also QTBUG-112006. diff --git a/src/corelib/time/qtimezonelocale.cpp b/src/corelib/time/qtimezonelocale.cpp index a794682fe0b..6ad4aa1479c 100644 --- a/src/corelib/time/qtimezonelocale.cpp +++ b/src/corelib/time/qtimezonelocale.cpp @@ -611,6 +611,27 @@ QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc // Custom zone with perverse m_id ? return; } + const auto isMixedCaseAbbrev = [tail](char ch) { + // cv-RU and en-GU abbreviate Chamorro as ChST + // scn-IT abbreviates Cuba as CuT/CuST/CuDT + // blo-BJ abbreviates GMT as Gk + switch (tail.size()) { + case 2: return tail == "Gk"; + case 3: return tail == "CuT"; + case 4: + if (tail[0] == 'C' && tail[1] == ch && tail[3] == 'T') { + switch (ch) { + case 'h': return tail[2] == 'S'; + case 'u': return tail[2] == 'S' || tail[2] == 'D'; + default: break; + } + } + return false; + default: + break; + } + return false; + }; // Even if it is abbr or city name, we don't care if we've found one before. bool maybeAbbr = ianaAbbrev.isEmpty(), maybeCityName = ianaTail.isEmpty(), inword = false; @@ -632,7 +653,7 @@ QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc maybeCityName = false; inword = false; } else if (QChar::isLower(ch)) { - maybeAbbr = false; + maybeAbbr = isMixedCaseAbbrev(ch); // Dar_es_Salaam shows both cases as word starts inword = true; } else if (QChar::isUpper(ch)) { @@ -891,8 +912,11 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, if (best.ianaIdIndex != invalidIanaId) return { QByteArray(ianaIdData + best.ianaIdIndex), best.nameLength, best.timeType }; - // Now try for a region format: - best = {}; + // Now try for a region format. + // Since we may get the IANA ID directly from a zone, we may not need an + // ianaIdIndex from CLDR-derived tables: and the active backend may know + // some zones newer than our latest CLDR. + NamePrefixMatch found; for (const qsizetype locInd : indices) { const LocaleZoneData &locData = localeZoneData[locInd]; const LocaleZoneData &nextData = localeZoneData[locInd + 1]; @@ -928,11 +952,11 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, QStringView city = row.exemplarCity().viewData(exemplarCityTable); if (textMatches(city)) { qsizetype length = cut + city.size() + suffix.size(); - if (length > best.nameLength) { - bool gotZone = row.ianaIdIndex == best.ianaIdIndex + if (length > found.nameLength) { + bool gotZone = row.ianaId() == found.ianaId // (cheap pre-test) || QTimeZone::isTimeZoneIdAvailable(row.ianaId().toByteArray()); if (gotZone) - best = { length, timeType, row.ianaIdIndex }; + found = { row.ianaId().toByteArray(), length, timeType }; } } } @@ -945,38 +969,16 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, QString city = QString::fromLatin1(local.replace('_', ' ')); if (textMatches(city)) { qsizetype length = cut + city.size() + suffix.size(); - if (length > best.nameLength) { - // Have to find iana in ianaIdData. Although its entries - // from locale-independent data are nicely sorted, the - // rest are (sadly) not. - QByteArrayView run(ianaIdData, qstrlen(ianaIdData)); - // std::size includes the trailing '\0', so subtract one: - const char *stop = ianaIdData + std::size(ianaIdData) - 1; - while (run != iana) { - if (run.end() < stop) { // Step to the next: - run = QByteArrayView(run.end() + 1); - } else { - run = QByteArrayView(); - break; - } - } - if (!run.isEmpty()) { - Q_ASSERT(run == iana); - const auto ianaIdIndex = run.begin() - ianaIdData; - Q_ASSERT(ianaIdIndex <= (std::numeric_limits<quint16>::max)()); - best = { length, timeType, quint16(ianaIdIndex) }; - } - } + if (length > found.nameLength) + found = { iana, length, timeType }; } } // TODO: similar for territories, at least once localeName() does so. } } - if (best.ianaIdIndex != invalidIanaId) - return { QByteArray(ianaIdData + best.ianaIdIndex), best.nameLength, best.timeType }; #undef localeRows - return {}; // No match found. + return found; } QTimeZonePrivate::NamePrefixMatch diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 556f7e21402..3f0254b1c5f 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -1177,7 +1177,7 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds) } Q_ASSERT(!name.isEmpty()); } else { // Fall back to a UTC-offset name: - name = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName); + name = isoOffsetFormat(offsetSeconds, QTimeZone::OffsetName); id = name.toUtf8(); } init(id, offsetSeconds, name, name, QLocale::AnyTerritory, name); @@ -1292,12 +1292,16 @@ QString QUtcTimeZonePrivate::displayName(QTimeZone::TimeType timeType, if (!(name.startsWith("GMT"_L1) || name.startsWith("UTC"_L1)) || name.size() < 5) return false; // Fallback drops trailing ":00" minute: - QStringView tail{avoid}; + QStringView tail{avoid}; // TODO: deal with sign earlier ! Also: invisible Unicode ! tail = tail.sliced(3); - if (tail.endsWith(":00"_L1)) - tail = tail.chopped(3); if (name.sliced(3) == tail) return true; + while (tail.endsWith(":00"_L1)) + tail = tail.chopped(3); + while (name.endsWith(":00"_L1)) + name = name.chopped(3); + if (name == tail) + return true; // Accept U+2212 as minus sign: const QChar sign = name[3] == u'\u2212' ? u'-' : name[3]; // Fallback doesn't zero-pad hour: diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h index 804c28af372..9a86ded6efb 100644 --- a/src/corelib/time/qtimezoneprivate_p.h +++ b/src/corelib/time/qtimezoneprivate_p.h @@ -50,7 +50,7 @@ class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData { // Nothing should be copy-assigning instances of either this or its derived // classes (only clone() should copy, using the copy-constructor): - bool operator=(const QTimeZonePrivate &) const = delete; + QTimeZonePrivate &operator=(const QTimeZonePrivate &) const = delete; protected: QTimeZonePrivate(const QTimeZonePrivate &other) = default; public: @@ -210,7 +210,7 @@ Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_RELOCATABLE_TYPE); class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QUtcTimeZonePrivate &) const = delete; + QUtcTimeZonePrivate &operator=(const QUtcTimeZonePrivate &) const = delete; QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other); public: // Create default UTC time zone @@ -273,7 +273,7 @@ private: #if QT_CONFIG(timezone_tzdb) class QChronoTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QChronoTimeZonePrivate &) const = delete; + QChronoTimeZonePrivate &operator=(const QChronoTimeZonePrivate &) const = delete; QChronoTimeZonePrivate(const QChronoTimeZonePrivate &) = default; public: QChronoTimeZonePrivate(); @@ -307,7 +307,7 @@ private: #elif defined(Q_OS_DARWIN) class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QMacTimeZonePrivate &) const = delete; + QMacTimeZonePrivate &operator=(const QMacTimeZonePrivate &) const = delete; QMacTimeZonePrivate(const QMacTimeZonePrivate &other); public: // Create default time zone @@ -353,7 +353,7 @@ private: #elif defined(Q_OS_ANDROID) class QAndroidTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QAndroidTimeZonePrivate &) const = delete; + QAndroidTimeZonePrivate &operator=(const QAndroidTimeZonePrivate &) const = delete; QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &) = default; public: // Create default time zone @@ -388,7 +388,7 @@ private: QJniObject androidTimeZone; }; -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) struct QTzTransitionTime { qint64 atMSecsSinceEpoch; @@ -421,7 +421,7 @@ struct QTzTimeZoneCacheEntry class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QTzTimeZonePrivate &) const = delete; + QTzTimeZonePrivate &operator=(const QTzTimeZonePrivate &) const = delete; QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default; public: // Create default time zone @@ -474,7 +474,7 @@ private: #elif QT_CONFIG(icu) class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QIcuTimeZonePrivate &) const = delete; + QIcuTimeZonePrivate &operator=(const QIcuTimeZonePrivate &) const = delete; QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other); public: // Create default time zone @@ -518,7 +518,7 @@ private: #elif defined(Q_OS_WIN) class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QWinTimeZonePrivate &) const = delete; + QWinTimeZonePrivate &operator=(const QWinTimeZonePrivate &) const = delete; QWinTimeZonePrivate(const QWinTimeZonePrivate &) = default; public: struct QWinTransitionRule { diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index 3d8ea595167..d517457027a 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -165,7 +165,7 @@ position between the second and third item, and returns the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -211,7 +211,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. @@ -260,7 +260,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -321,7 +321,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to remove items as you iterate over the set, use remove(). @@ -718,7 +718,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -768,7 +768,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -819,7 +819,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. For example: @@ -867,7 +867,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -931,7 +931,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -994,7 +994,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. For example: diff --git a/src/corelib/tools/quniquehandle_p.h b/src/corelib/tools/quniquehandle_p.h index 3ba557e838d..fd6ab693912 100644 --- a/src/corelib/tools/quniquehandle_p.h +++ b/src/corelib/tools/quniquehandle_p.h @@ -18,6 +18,7 @@ #include <QtCore/qtconfigmacros.h> #include <QtCore/qassert.h> #include <QtCore/qcompare.h> +#include <QtCore/qfunctionaltools_impl.h> #include <QtCore/qswap.h> #include <QtCore/qtclasshelpermacros.h> @@ -99,6 +100,42 @@ QT_BEGIN_NAMESPACE ... + Example 3: + + struct TempFileTraits { + using Type = FILE*; + + static Type invalidValue() { + return nullptr; + } + + static bool close(Type handle) { + return fclose(handle) == 0; + } + }; + + struct TempFileDeleter { + using Type = TempFileTraits::Type; + + void operator()(Type handle) { + if (handle != TempFileTraits::invalidValue()) { + TempFileTraits::close(handle); + if (path) + remove(path); + } + } + + const char* path{ nullptr }; + }; + + using TempFileHandle = QUniqueHandle<TempFileTraits, TempFileDeleter>; + + Usage: + + TempFileHandle tempFile(fopen("temp.bin", "wb"), TempFileDeleter{ "my_temp.bin" }); + + ... + NOTE: The QUniqueHandle assumes that closing a resource is guaranteed to succeed, and provides no support for handling failure to close a resource. It is therefore only recommended for use cases @@ -108,9 +145,32 @@ QT_BEGIN_NAMESPACE // clang-format off +namespace QtUniqueHandleTraits { + template <typename HandleTraits> -class QUniqueHandle +struct DefaultDeleter { + using Type = typename HandleTraits::Type; + + void operator()(Type handle) const noexcept + { + if (handle != HandleTraits::invalidValue()) { + const bool success = HandleTraits::close(handle); + Q_ASSERT(success); + } + } +}; + +} // namespace QtUniqueHandleTraits + +template <typename HandleTraits, typename Deleter = QtUniqueHandleTraits::DefaultDeleter<HandleTraits>> +class QUniqueHandle : private QtPrivate::CompactStorage<Deleter> +{ + using Storage = QtPrivate::CompactStorage<Deleter>; + + template <typename D> + using if_default_constructible = std::enable_if_t<std::is_default_constructible_v<D>, bool>; + public: using Type = typename HandleTraits::Type; static_assert(std::is_nothrow_default_constructible_v<Type>); @@ -120,6 +180,11 @@ public: static_assert(std::is_nothrow_copy_assignable_v<Type>); static_assert(std::is_nothrow_move_assignable_v<Type>); static_assert(std::is_nothrow_destructible_v<Type>); + static_assert(std::is_nothrow_copy_constructible_v<Deleter>); + static_assert(std::is_nothrow_move_constructible_v<Deleter>); + static_assert(std::is_nothrow_copy_assignable_v<Deleter>); + static_assert(std::is_nothrow_move_assignable_v<Deleter>); + static_assert(std::is_nothrow_destructible_v<Deleter>); static_assert(noexcept(std::declval<Type>() == std::declval<Type>())); static_assert(noexcept(std::declval<Type>() != std::declval<Type>())); static_assert(noexcept(std::declval<Type>() < std::declval<Type>())); @@ -127,16 +192,24 @@ public: static_assert(noexcept(std::declval<Type>() > std::declval<Type>())); static_assert(noexcept(std::declval<Type>() >= std::declval<Type>())); - QUniqueHandle() = default; - - explicit QUniqueHandle(const Type &handle) noexcept + template <if_default_constructible<Deleter> = true> + explicit QUniqueHandle(const Type& handle = HandleTraits::invalidValue()) noexcept : m_handle{ handle } {} - QUniqueHandle(QUniqueHandle &&other) noexcept - : m_handle{ other.release() } + QUniqueHandle(const Type &handle, const Deleter &deleter) noexcept + : Storage{ deleter }, m_handle{ handle } + {} + + QUniqueHandle(const Type &handle, Deleter &&deleter) noexcept + : Storage{ std::move(deleter) }, m_handle{ handle } {} + QUniqueHandle(QUniqueHandle &&other) noexcept + : Storage{ std::move(other.deleter()) }, m_handle{ other.release() } + { + } + ~QUniqueHandle() noexcept { close(); @@ -145,6 +218,7 @@ public: void swap(QUniqueHandle &other) noexcept { qSwap(m_handle, other.m_handle); + qSwap(deleter(), other.deleter()); } QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QUniqueHandle) @@ -168,6 +242,16 @@ public: return m_handle; } + [[nodiscard]] Deleter& deleter() noexcept + { + return Storage::object(); + } + + [[nodiscard]] const Deleter& deleter() const noexcept + { + return Storage::object(); + } + void reset(const Type& handle = HandleTraits::invalidValue()) noexcept { if (handle == m_handle) @@ -193,8 +277,7 @@ public: if (!isValid()) return; - const bool success = HandleTraits::close(m_handle); - Q_ASSERT(success); + deleter()(m_handle); m_handle = HandleTraits::invalidValue(); } @@ -222,8 +305,8 @@ private: // clang-format on -template <typename Trait> -void swap(QUniqueHandle<Trait> &lhs, QUniqueHandle<Trait> &rhs) noexcept +template <typename Trait, typename Deleter> +void swap(QUniqueHandle<Trait, Deleter> &lhs, QUniqueHandle<Trait, Deleter> &rhs) noexcept { lhs.swap(rhs); } diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake index ad76bb095a0..5001f2deeec 100644 --- a/src/gui/configure.cmake +++ b/src/gui/configure.cmake @@ -1217,17 +1217,6 @@ qt_feature("xcb-egl-plugin" PRIVATE CONDITION QT_FEATURE_egl AND QT_FEATURE_opengl EMIT_IF QT_FEATURE_xcb ) -qt_feature("xcb-native-painting" PRIVATE - LABEL "Native painting (experimental)" - AUTODETECT OFF - CONDITION QT_FEATURE_xcb_xlib AND QT_FEATURE_fontconfig AND XRender_FOUND - EMIT_IF QT_FEATURE_xcb -) -qt_feature("xrender" PRIVATE - LABEL "XRender for native painting" - CONDITION QT_FEATURE_xcb_native_painting - EMIT_IF QT_FEATURE_xcb AND QT_FEATURE_xcb_native_painting -) qt_feature("xcb-xlib" PRIVATE LABEL "XCB Xlib" CONDITION QT_FEATURE_xlib AND X11_XCB_FOUND diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 6ba113ef8fb..4a8b409379c 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -47,6 +47,9 @@ #include <memory> +#define QT_XFORM_TYPE_MSBFIRST 0 +#define QT_XFORM_TYPE_LSBFIRST 1 + QT_BEGIN_NAMESPACE class QCmyk32; @@ -4447,6 +4450,8 @@ int QImage::metric(PaintDeviceMetric metric) const trigx += m11; \ trigy += m12; // END OF MACRO + +static bool qt_xForm_helper(const QTransform &trueMat, int xoffset, int type, int depth, uchar *dptr, qsizetype dbpl, int p_inc, int dHeight, const uchar *sptr, qsizetype sbpl, int sWidth, int sHeight) diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h index 5621afa4da5..3346ca85375 100644 --- a/src/gui/image/qplatformpixmap.h +++ b/src/gui/image/qplatformpixmap.h @@ -33,7 +33,7 @@ public: enum ClassId { RasterClass, DirectFBClass, BlitterClass, Direct2DClass, - X11Class, CustomClass = 1024 }; + CustomClass = 1024 }; QPlatformPixmap(PixelType pixelType, int classId); virtual ~QPlatformPixmap(); @@ -111,7 +111,6 @@ protected: private: friend class QPixmap; - friend class QX11PlatformPixmap; friend class QImagePixmapCleanupHooks; // Needs to set is_cached int detach_no; @@ -122,10 +121,6 @@ private: uint is_cached; }; -# define QT_XFORM_TYPE_MSBFIRST 0 -# define QT_XFORM_TYPE_LSBFIRST 1 -Q_GUI_EXPORT bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, qsizetype, int, int, const uchar*, qsizetype, int, int); - QT_END_NAMESPACE #endif // QPLATFORMPIXMAP_H diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index ae730a9b3af..7b1e76cc78f 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1146,6 +1146,33 @@ Q_IMPL_POINTER_EVENT(QHoverEvent) */ /*! + \property QWheelEvent::device + \brief the device from which the wheel event originated + + \sa pointingDevice() +*/ + +/*! + \property QWheelEvent::inverted + \since 5.7 + \brief whether the delta values delivered with the event are inverted + + Normally, a vertical wheel will produce a QWheelEvent with positive delta + values if the top of the wheel is rotating away from the hand operating it. + Similarly, a horizontal wheel movement will produce a QWheelEvent with + positive delta values if the top of the wheel is moved to the left. + + However, on some platforms this is configurable, so that the same + operations described above will produce negative delta values (but with the + same magnitude). With the inverted property a wheel event consumer can + choose to always follow the direction of the wheel, regardless of the + system settings, but only for specific widgets. + + \note Many platforms provide no such information. On such platforms + \l inverted always returns false. +*/ + +/*! \fn bool QWheelEvent::inverted() const \since 5.7 @@ -1236,6 +1263,24 @@ bool QWheelEvent::isEndEvent() const #endif // QT_CONFIG(wheelevent) /*! + \property QWheelEvent::pixelDelta + \brief the scrolling distance in pixels on screen + + This value is provided on platforms that support high-resolution + pixel-based delta values, such as \macos. The value should be used + directly to scroll content on screen. + + \note On platforms that support scrolling \l{phase()}{phases}, the delta + may be null when scrolling is about to begin (Qt::ScrollBegin) or has + ended (Qt::ScrollEnd). + + \note On X11 this value is driver-specific and unreliable, use + angleDelta() instead. + + \sa angleDelta() +*/ + +/*! \fn QPoint QWheelEvent::pixelDelta() const Returns the scrolling distance in pixels on screen. This value is @@ -1256,6 +1301,27 @@ bool QWheelEvent::isEndEvent() const */ /*! + \property QWheelEvent::angleDelta + \brief the relative amount that the wheel was rotated, in eighths of a degree + + A positive value indicates that the wheel was rotated forwards away from the + user; a negative value indicates that the wheel was rotated backwards toward + the user. \c angleDelta().y() provides the angle through which the common + vertical mouse wheel was rotated since the previous event. \c angleDelta().x() + provides the angle through which the horizontal mouse wheel was rotated, if + the mouse has a horizontal wheel; otherwise it stays at zero. + + Most mouse types work in steps of 15 degrees, in which case the delta value + is a multiple of 120; i.e., 120 units * 1/8 = 15 degrees. + + \note On platforms that support scrolling \l{phase()}{phases}, the delta + may be null when scrolling is about to begin (Qt::ScrollBegin) or has + ended (Qt::ScrollEnd). + + \sa pixelDelta() +*/ + +/*! \fn QPoint QWheelEvent::angleDelta() const Returns the relative amount that the wheel was rotated, in eighths of a @@ -1294,6 +1360,15 @@ bool QWheelEvent::isEndEvent() const */ /*! + \property QWheelEvent::phase + \since 5.2 + \brief the scrolling phase of this wheel event + + \note The Qt::ScrollBegin and Qt::ScrollEnd phases are currently + supported only on \macos. +*/ + +/*! \fn Qt::ScrollPhase QWheelEvent::phase() const \since 5.2 diff --git a/src/gui/kernel/qinputdevice.cpp b/src/gui/kernel/qinputdevice.cpp index 8e5c38922e0..caed0fc6135 100644 --- a/src/gui/kernel/qinputdevice.cpp +++ b/src/gui/kernel/qinputdevice.cpp @@ -187,6 +187,11 @@ QString QInputDevice::name() const } /*! + \property QInputDevice::type + \brief the device type +*/ + +/*! Returns the device type. */ QInputDevice::DeviceType QInputDevice::type() const diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp index dcce354688a..7062340b287 100644 --- a/src/gui/kernel/qpointingdevice.cpp +++ b/src/gui/kernel/qpointingdevice.cpp @@ -241,6 +241,11 @@ void QPointingDevice::setMaximumTouchPoints(int c) #endif // QT_DEPRECATED_SINCE(6, 0) /*! + \property QPointingDevice::pointerType + \brief the pointer type +*/ + +/*! Returns the pointer type. */ QPointingDevice::PointerType QPointingDevice::pointerType() const @@ -250,6 +255,12 @@ QPointingDevice::PointerType QPointingDevice::pointerType() const } /*! + \property QPointingDevice::maximumPoints + \brief the maximum number of simultaneous touch points (fingers) that + can be detected +*/ + +/*! Returns the maximum number of simultaneous touch points (fingers) that can be detected. */ @@ -260,6 +271,11 @@ int QPointingDevice::maximumPoints() const } /*! + \property QPointingDevice::buttonCount + \brief the maximum number of on-device buttons that can be detected +*/ + +/*! Returns the maximum number of on-device buttons that can be detected. */ int QPointingDevice::buttonCount() const @@ -269,6 +285,13 @@ int QPointingDevice::buttonCount() const } /*! + \property QPointingDevice::uniqueId + \brief a unique ID (of dubious utility) for the device + + You probably should rather be concerned with QPointerEventPoint::uniqueId(). +*/ + +/*! Returns a unique ID (of dubious utility) for the device. You probably should rather be concerned with QPointerEventPoint::uniqueId(). diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index d27539b2419..c9df5d28a45 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -301,6 +301,8 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, const QFixedPoint &subPixelPosition) { QImage mask = textureMapForGlyph(g, subPixelPosition); + if (mask.isNull()) + return; #ifdef CACHE_DEBUG printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height()); diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 62b7ab6efb0..5590f2fb431 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -7186,6 +7186,26 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const */ /*! + \fn bool QRhiGraphicsPipeline::hasDepthClamp() const + \return true if depth clamp is enabled. + + \since 6.11 + */ + +/*! + \fn void QRhiGraphicsPipeline::setDepthClamp(bool enable) + + Enables depth clamping when \a enable is true. When depth clamping is + enabled, primitives that would otherwise be clipped by the near or far + clip plane are rasterized and their depth values are clamped to the + depth range. When disabled (the default), such primitives are clipped. + + \note This setting is ignored on OpenGL ES. + + \since 6.11 + */ + +/*! \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const \return the depth comparison function. */ diff --git a/src/gui/rhi/qrhi.h b/src/gui/rhi/qrhi.h index b5a3f7b43be..5ee2a9acd13 100644 --- a/src/gui/rhi/qrhi.h +++ b/src/gui/rhi/qrhi.h @@ -1453,6 +1453,9 @@ public: bool hasDepthWrite() const { return m_depthWrite; } void setDepthWrite(bool enable) { m_depthWrite = enable; } + bool hasDepthClamp() const { return m_depthClamp; } + void setDepthClamp(bool enable) { m_depthClamp = enable; } + CompareOp depthOp() const { return m_depthOp; } void setDepthOp(CompareOp op) { m_depthOp = op; } @@ -1524,6 +1527,7 @@ protected: QVarLengthArray<TargetBlend, 8> m_targetBlends; bool m_depthTest = false; bool m_depthWrite = false; + bool m_depthClamp = false; CompareOp m_depthOp = Less; bool m_stencilTest = false; StencilOpState m_stencilFront; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index a5f860e7724..1441be24043 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -4673,7 +4673,7 @@ bool QD3D11GraphicsPipeline::create() rastDesc.FrontCounterClockwise = m_frontFace == CCW; rastDesc.DepthBias = m_depthBias; rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias; - rastDesc.DepthClipEnable = true; + rastDesc.DepthClipEnable = m_depthClamp ? FALSE : TRUE; rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor); rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1; HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState); diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp index 4f09b3c136b..b68b65b1063 100644 --- a/src/gui/rhi/qrhid3d12.cpp +++ b/src/gui/rhi/qrhid3d12.cpp @@ -6263,7 +6263,7 @@ bool QD3D12GraphicsPipeline::create() stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW; stream.rasterizerState.object.DepthBias = m_depthBias; stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias; - stream.rasterizerState.object.DepthClipEnable = TRUE; + stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE; stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1; stream.depthStencilState.object.DepthEnable = m_depthTest; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 15f5cd8f7e8..1308d4362e5 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -585,6 +585,10 @@ QT_BEGIN_NAMESPACE #define GL_PROGRAM 0x82E2 #endif +#ifndef GL_DEPTH_CLAMP +#define GL_DEPTH_CLAMP 0x864F +#endif + /*! Constructs a new QRhiGles2InitParams. @@ -998,6 +1002,13 @@ bool QRhiGles2::create(QRhi::Flags flags) } if (caps.gles) + caps.depthClamp = false; + else + caps.depthClamp = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // Desktop 3.2 + if (!caps.depthClamp) + caps.depthClamp = ctx->hasExtension("GL_EXT_depth_clamp") || ctx->hasExtension("GL_ARB_depth_clamp"); + + if (caps.gles) caps.textureCompareMode = caps.ctxMajor >= 3; // ES 3.0 else caps.textureCompareMode = true; @@ -3959,6 +3970,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) break; case QGles2CommandBuffer::Command::InvalidateFramebuffer: if (caps.gles && caps.ctxMajor >= 3) { + f->glBindFramebuffer(GL_FRAMEBUFFER, cmd.args.invalidateFramebuffer.fbo); f->glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, cmd.args.invalidateFramebuffer.attCount, cmd.args.invalidateFramebuffer.att); @@ -4095,6 +4107,15 @@ void QRhiGles2::executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2Grap f->glDepthMask(depthWrite); } + const bool depthClamp = psD->m_depthClamp; + if (caps.depthClamp && (forceUpdate || depthClamp != state.depthClamp)) { + state.depthClamp = depthClamp; + if (depthClamp) + f->glEnable(GL_DEPTH_CLAMP); + else + f->glDisable(GL_DEPTH_CLAMP); + } + const GLenum depthFunc = toGlCompareOp(psD->m_depthOp); if (forceUpdate || depthFunc != state.depthFunc) { state.depthFunc = depthFunc; @@ -4881,6 +4902,7 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource if (mayDiscardDepthStencil) { QGles2CommandBuffer::Command &cmd(cbD->commands.get()); cmd.cmd = QGles2CommandBuffer::Command::InvalidateFramebuffer; + cmd.args.invalidateFramebuffer.fbo = rtTex->framebuffer; if (caps.needsDepthStencilCombinedAttach) { cmd.args.invalidateFramebuffer.attCount = 1; cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_STENCIL_ATTACHMENT; diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h index 725e71a3665..70dd96a8dc7 100644 --- a/src/gui/rhi/qrhigles2_p.h +++ b/src/gui/rhi/qrhigles2_p.h @@ -547,6 +547,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer GLbitfield barriers; } barrier; struct { + GLuint fbo; int attCount; GLenum att[3]; } invalidateFramebuffer; @@ -592,6 +593,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer } blend[16]; bool depthTest; bool depthWrite; + bool depthClamp; GLenum depthFunc; bool stencilTest; GLuint stencilReadMask; @@ -1074,6 +1076,7 @@ public: uint baseVertex : 1; uint compute : 1; uint textureCompareMode : 1; + uint depthClamp : 1; uint properMapBuffer : 1; uint nonBaseLevelFramebufferTexture : 1; uint texelFetch : 1; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index c3f1031b44b..7fa05f69232 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -403,6 +403,7 @@ struct QMetalGraphicsPipelineData MTLWinding winding; MTLCullMode cullMode; MTLTriangleFillMode triangleFillMode; + MTLDepthClipMode depthClipMode; float depthBias; float slopeScaledDepthBias; QMetalShader vs; @@ -1477,7 +1478,6 @@ void QMetalGraphicsPipeline::makeActiveForCurrentRenderPassEncoder(QMetalCommand [cbD->d->currentRenderPassEncoder setDepthStencilState: d->ds]; cbD->d->currentDepthStencilState = d->ds; } - if (cbD->currentCullMode == -1 || d->cullMode != uint(cbD->currentCullMode)) { [cbD->d->currentRenderPassEncoder setCullMode: d->cullMode]; cbD->currentCullMode = int(d->cullMode); @@ -1486,6 +1486,10 @@ void QMetalGraphicsPipeline::makeActiveForCurrentRenderPassEncoder(QMetalCommand [cbD->d->currentRenderPassEncoder setTriangleFillMode: d->triangleFillMode]; cbD->currentTriangleFillMode = int(d->triangleFillMode); } + if (cbD->currentDepthClipMode == -1 || d->depthClipMode != uint(cbD->currentDepthClipMode)) { + [cbD->d->currentRenderPassEncoder setDepthClipMode: d->depthClipMode]; + cbD->currentDepthClipMode = int(d->depthClipMode); + } if (cbD->currentFrontFaceWinding == -1 || d->winding != uint(cbD->currentFrontFaceWinding)) { [cbD->d->currentRenderPassEncoder setFrontFacingWinding: d->winding]; cbD->currentFrontFaceWinding = int(d->winding); @@ -5035,6 +5039,7 @@ void QMetalGraphicsPipeline::mapStates() d->winding = m_frontFace == CCW ? MTLWindingCounterClockwise : MTLWindingClockwise; d->cullMode = toMetalCullMode(m_cullMode); d->triangleFillMode = toMetalTriangleFillMode(m_polygonMode); + d->depthClipMode = m_depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip; d->depthBias = float(m_depthBias); d->slopeScaledDepthBias = m_slopeScaledDepthBias; } @@ -6257,6 +6262,7 @@ void QMetalCommandBuffer::resetPerPassCachedState() currentIndexFormat = QRhiCommandBuffer::IndexUInt16; currentCullMode = -1; currentTriangleFillMode = -1; + currentDepthClipMode = -1; currentFrontFaceWinding = -1; currentDepthBiasValues = { 0.0f, 0.0f }; diff --git a/src/gui/rhi/qrhimetal_p.h b/src/gui/rhi/qrhimetal_p.h index 7c19ae9e767..6649a6cd304 100644 --- a/src/gui/rhi/qrhimetal_p.h +++ b/src/gui/rhi/qrhimetal_p.h @@ -299,6 +299,7 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer QRhiCommandBuffer::IndexFormat currentIndexFormat; int currentCullMode; int currentTriangleFillMode; + int currentDepthClipMode; int currentFrontFaceWinding; std::pair<float, float> currentDepthBiasValues; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index c5167a6e7de..481ffd57b5d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -949,6 +949,8 @@ bool QRhiVulkan::create(QRhi::Flags flags) // elsewhere states that the minimum bufferOffset is 4... texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment); + caps.depthClamp = physDevFeatures.depthClamp; + caps.wideLines = physDevFeatures.wideLines; caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1); @@ -8402,6 +8404,8 @@ bool QVkGraphicsPipeline::create() VkPipelineRasterizationStateCreateInfo rastInfo = {}; rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + if (m_depthClamp && rhiD->caps.depthClamp) + rastInfo.depthClampEnable = m_depthClamp; rastInfo.cullMode = toVkCullMode(m_cullMode); rastInfo.frontFace = toVkFrontFace(m_frontFace); if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) { diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d141a84c5fb..1e9318513fd 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -936,6 +936,7 @@ public: struct { bool compute = false; + bool depthClamp = false; bool wideLines = false; bool debugUtils = false; bool vertexAttribDivisor = false; diff --git a/src/gui/text/qfontvariableaxis.cpp b/src/gui/text/qfontvariableaxis.cpp index be83a3e02ce..bbc14f4cd11 100644 --- a/src/gui/text/qfontvariableaxis.cpp +++ b/src/gui/text/qfontvariableaxis.cpp @@ -60,6 +60,18 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QFontVariableAxisPrivate) QFontVariableAxis::QFontVariableAxis(const QFontVariableAxis &axis) = default; /*! + \property QFontVariableAxis::tag + \brief the tag of the axis + + This is a four-character sequence which identifies the axis. Certain tags + have standardized meanings, such as "wght" (weight) and "wdth" (width), + but any sequence of four latin-1 characters is a valid tag. By convention, + non-standard/custom axes are denoted by tags in all uppercase. + + \sa QFont::setVariableAxis(), name() +*/ + +/*! Returns the tag of the axis. This is a four-character sequence which identifies the axis. Certain tags have standardized meanings, such as "wght" (weight) and "wdth" (width), but any sequence of four latin-1 characters is a valid tag. By convention, non-standard/custom axes @@ -91,6 +103,13 @@ void QFontVariableAxis::setTag(QFont::Tag tag) } /*! + \property QFontVariableAxis::name + \brief the name of the axis, if provided by the font + + \sa tag() +*/ + +/*! Returns the name of the axis, if provided by the font. \sa tag() @@ -153,6 +172,15 @@ void QFontVariableAxis::setMinimumValue(qreal minimumValue) } /*! + \property QFontVariableAxis::maximumValue + \brief the maximum value of the axis + + Setting the axis to a value which is higher than this is not supported. + + \sa minimumValue(), defaultValue() +*/ + +/*! Returns the maximum value of the axis. Setting the axis to a value which is higher than this is not supported. @@ -182,6 +210,16 @@ void QFontVariableAxis::setMaximumValue(qreal maximumValue) } /*! + \property QFontVariableAxis::defaultValue + \brief the default value of the axis + + This is the value the axis will have if none has been provided in the + QFont query. + + \sa minimumValue(), maximumValue() +*/ + +/*! Returns the default value of the axis. This is the value the axis will have if none has been provided in the QFont query. diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index f680950701c..f76d79571c3 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -272,6 +272,11 @@ void QNetworkReplyHttpImpl::close() void QNetworkReplyHttpImpl::abort() { + abortImpl(QNetworkReply::OperationCanceledError); +} + +void QNetworkReplyHttpImpl::abortImpl(QNetworkReply::NetworkError error) +{ Q_D(QNetworkReplyHttpImpl); // FIXME if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) @@ -282,7 +287,8 @@ void QNetworkReplyHttpImpl::abort() if (d->state != QNetworkReplyPrivate::Finished) { // call finished which will emit signals // FIXME shouldn't this be emitted Queued? - d->error(OperationCanceledError, tr("Operation canceled")); + d->error(error, + error == TimeoutError ? tr("Operation timed out") : tr("Operation canceled")); d->finished(); } @@ -2120,7 +2126,7 @@ void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData() void QNetworkReplyHttpImplPrivate::_q_transferTimedOut() { Q_Q(QNetworkReplyHttpImpl); - q->abort(); + q->abortImpl(QNetworkReply::TimeoutError); } void QNetworkReplyHttpImplPrivate::setupTransferTimeout() @@ -2242,8 +2248,10 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c // Can't set and emit multiple errors. if (errorCode != QNetworkReply::NoError) { // But somewhat unavoidable if we have cancelled the request: - if (errorCode != QNetworkReply::OperationCanceledError) + if (errorCode != QNetworkReply::OperationCanceledError + && errorCode != QNetworkReply::TimeoutError) { qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once."); + } return; } diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 0d16d02ff53..a354b388ad6 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -59,6 +59,7 @@ public: void close() override; void abort() override; + void abortImpl(QNetworkReply::NetworkError error); qint64 bytesAvailable() const override; bool isSequential () const override; qint64 size() const override; diff --git a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp index 62d24eefd33..e5ada714ba5 100644 --- a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp +++ b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp @@ -110,7 +110,8 @@ QGlibNetworkInformationBackend::QGlibNetworkInformationBackend() connectivityHandlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity", G_CALLBACK(updateConnectivity), this); - networkHandlerId = g_signal_connect_swapped(networkMonitor, "network-changed", + // needed until GLib 2.86 for netlink support + networkHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-available", G_CALLBACK(updateConnectivity), this); meteredHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-metered", diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index e0ef6cec794..4c4e5fac962 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -491,7 +491,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; return; if (m_panel.visible) { - const QString selection = QString::fromNSString(m_panel.URL.path); + const QString selection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C); if (selection != m_currentSelection) { m_currentSelection = selection; emit m_helper->currentChanged(QUrl::fromLocalFile(selection)); diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm index dab348beaa4..7a6f010ba8f 100644 --- a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm +++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm @@ -88,6 +88,11 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w return false; } + // Tahoe has issues with window-modal alert buttons not responding to mouse + if (windowModality == Qt::WindowModal + && QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe) + return false; + // And without options we don't know what to show if (!options()) return false; diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index a87c33c8346..5807d157636 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -586,14 +586,7 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface) void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, bool visible) { emscripten::val element = getHtmlElement(iface); - - if (visible) { - setAttribute(element, "aria-hidden", false); - setAttribute(element, "tabindex", ""); - } else { - setAttribute(element, "aria-hidden", true); // aria-hidden mean completely hidden; maybe some sort of soft-hidden should be used. - setAttribute(element, "tabindex", "-1"); - } + setAttribute(element, "aria-hidden", !visible); } void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface) diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp index 0ccc4dba57a..5ab285ad97d 100644 --- a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp @@ -192,10 +192,12 @@ void QWaylandInputContext::setFocusObject(QObject *object) if (window && window->handle()) { if (mCurrentWindow.data() != window) { if (!inputMethodAccepted()) { - auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface(); - if (surface) - inputInterface->disableSurface(surface); - mCurrentWindow.clear(); + if (mCurrentWindow) { + auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface(); + if (surface) + inputInterface->disableSurface(surface); + mCurrentWindow.clear(); + } } else { auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface(); if (surface) { diff --git a/src/plugins/platforms/windows/qwindowsiconengine.cpp b/src/plugins/platforms/windows/qwindowsiconengine.cpp index 71103183183..edc1ea3a9dc 100644 --- a/src/plugins/platforms/windows/qwindowsiconengine.cpp +++ b/src/plugins/platforms/windows/qwindowsiconengine.cpp @@ -63,8 +63,8 @@ static QString getGlyphs(QStringView iconName) {"go-home"_L1, u"\ue80f"}, // {"go-jump"_L1, u"\uf719"}, //{"go-last"_L1, u"\ue5dd"}, - {"go-next"_L1, u"\ue893"}, - {"go-previous"_L1, u"\ue892"}, + {"go-next"_L1, u"\ue72a"}, + {"go-previous"_L1, u"\ue72b"}, //{"go-top"_L1, u"\ue25a"}, {"go-up"_L1, u"\ue74a"}, {"help-about"_L1, u"\ue946"}, @@ -100,7 +100,7 @@ static QString getGlyphs(QStringView iconName) //{"object-flip-vertical"_L1, u"\u"}, {"object-rotate-left"_L1, u"\ue80c"}, {"object-rotate-right"_L1, u"\ue80d"}, - //{"process-stop"_L1, u"\ue5c9"}, + {"process-stop"_L1, u"\uf140"}, {"system-lock-screen"_L1, u"\uee3f"}, {"system-log-out"_L1, u"\uf3b1"}, //{"system-run"_L1, u"\u"}, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8e3ab67ced5..72daffb56b1 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -466,15 +466,17 @@ static bool applyBlurBehindWindow(HWND hwnd) return result; } +static bool shouldShowTitlebarButton(Qt::WindowFlags flags, Qt::WindowFlags button) +{ + return !flags.testFlag(Qt::CustomizeWindowHint) || flags.testFlags(Qt::CustomizeWindowHint | button); +} + // from qwidget_win.cpp, pass flags separately in case they have been "autofixed". static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags) { - if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint)) - return false; - // if the user explicitly asked for the maximize button, we try to add - // it even if the window has fixed size. - return (flags & Qt::CustomizeWindowHint) || - w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX); + return !flags.testFlag(Qt::MSWindowsFixedSizeDialogHint) && + (shouldShowTitlebarButton(flags, Qt::WindowMaximizeButtonHint) || + w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } bool QWindowsWindow::hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags) @@ -805,6 +807,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if (topLevel) { if ((type == Qt::Window || dialog || tool)) { + const bool defaultTitlebar = !flags.testFlag(Qt::CustomizeWindowHint); if (!(flags & Qt::FramelessWindowHint)) { style |= WS_POPUP; if (flags & Qt::MSWindowsFixedSizeDialogHint) { @@ -812,16 +815,16 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } else { style |= WS_THICKFRAME; } - if (flags & Qt::WindowTitleHint) + if (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint)) style |= WS_CAPTION; // Contains WS_DLGFRAME } - if (flags & Qt::WindowSystemMenuHint) + if (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowSystemMenuHint)) style |= WS_SYSMENU; - else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) { + else if (dialog && (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint)) && !(flags & Qt::FramelessWindowHint)) { style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. exStyle |= WS_EX_DLGMODALFRAME; } - const bool showMinimizeButton = flags & Qt::WindowMinimizeButtonHint; + const bool showMinimizeButton = shouldShowTitlebarButton(flags, Qt::WindowMinimizeButtonHint); if (showMinimizeButton) style |= WS_MINIMIZEBOX; const bool showMaximizeButton = shouldShowMaximizeButton(w, flags); diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt index 492d274c2fd..204acd72ba0 100644 --- a/src/plugins/platforms/xcb/CMakeLists.txt +++ b/src/plugins/platforms/xcb/CMakeLists.txt @@ -120,30 +120,6 @@ qt_internal_extend_target(XcbQpaPrivate CONDITION CLANG -ftemplate-depth=1024 ) -qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_native_painting - SOURCES - nativepainting/qbackingstore_x11.cpp nativepainting/qbackingstore_x11_p.h - nativepainting/qcolormap_x11.cpp nativepainting/qcolormap_x11_p.h - nativepainting/qpaintengine_x11.cpp nativepainting/qpaintengine_x11_p.h - nativepainting/qpixmap_x11.cpp nativepainting/qpixmap_x11_p.h - nativepainting/qpolygonclipper_p.h - nativepainting/qt_x11_p.h - nativepainting/qtessellator.cpp nativepainting/qtessellator_p.h - nativepainting/qxcbnativepainting.cpp nativepainting/qxcbnativepainting.h - INCLUDE_DIRECTORIES - nativepainting -) - -qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_xcb_native_painting AND QT_FEATURE_xrender - PUBLIC_LIBRARIES - PkgConfig::XRender -) - -qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_fontconfig AND QT_FEATURE_xcb_native_painting - LIBRARIES - WrapFreetype::WrapFreetype -) - if(QT_FEATURE_system_xcb_xinput) qt_internal_extend_target(XcbQpaPrivate LIBRARIES XCB::XINPUT) else() diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp deleted file mode 100644 index 1ac5f6a64bc..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp +++ /dev/null @@ -1,175 +0,0 @@ -// 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 - -#include "qbackingstore_x11_p.h" -#include "qxcbwindow.h" -#include "qpixmap_x11_p.h" - -#include <private/qhighdpiscaling_p.h> -#include <QPainter> - -#if QT_CONFIG(xrender) -# include <X11/extensions/Xrender.h> -#endif - -#define register /* C++17 deprecated register */ -#include <X11/Xlib.h> -#undef register - -QT_BEGIN_NAMESPACE - -QXcbNativeBackingStore::QXcbNativeBackingStore(QWindow *window) - : QPlatformBackingStore(window) - , m_translucentBackground(false) -{ - if (QXcbWindow *w = static_cast<QXcbWindow *>(window->handle())) { - m_translucentBackground = w->connection()->hasXRender() && - QImage::toPixelFormat(w->imageFormat()).alphaUsage() == QPixelFormat::UsesAlpha; - } -} - -QXcbNativeBackingStore::~QXcbNativeBackingStore() -{} - -QPaintDevice *QXcbNativeBackingStore::paintDevice() -{ - return &m_pixmap; -} - -void QXcbNativeBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - if (m_pixmap.isNull()) - return; - - QSize pixmapSize = m_pixmap.size(); - - QRegion clipped = region; - clipped &= QRect(QPoint(), QHighDpi::toNativePixels(window->size(), window)); - clipped &= QRect(0, 0, pixmapSize.width(), pixmapSize.height()).translated(-offset); - - QRect br = clipped.boundingRect(); - if (br.isNull()) - return; - - QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); - if (!platformWindow) { - qWarning("QXcbBackingStore::flush: QWindow has no platform window (QTBUG-32681)"); - return; - } - - Window wid = platformWindow->xcb_window(); - Pixmap pid = qt_x11PixmapHandle(m_pixmap); - - QList<XRectangle> clipRects = qt_region_to_xrectangles(clipped); - -#if QT_CONFIG(xrender) - if (m_translucentBackground) - { - XWindowAttributes attrib; - XGetWindowAttributes(display(), wid, &attrib); - XRenderPictFormat *format = XRenderFindVisualFormat(display(), attrib.visual); - - Picture srcPic = qt_x11PictureHandle(m_pixmap); - Picture dstPic = XRenderCreatePicture(display(), wid, format, 0, 0); - - XRenderSetPictureClipRectangles(display(), dstPic, 0, 0, clipRects.constData(), clipRects.size()); - - XRenderComposite(display(), PictOpSrc, srcPic, 0L /*None*/, dstPic, br.x() + offset.x(), - br.y() + offset.y(), 0, 0, br.x(), br.y(), br.width(), br.height()); - - XRenderFreePicture(display(), dstPic); - } - else -#endif - { - GC gc = XCreateGC(display(), wid, 0, nullptr); - - if (clipRects.size() != 1) - XSetClipRectangles(display(), gc, 0, 0, clipRects.data(), clipRects.size(), YXBanded); - - XCopyArea(display(), pid, wid, gc, br.x() + offset.x(), br.y() + offset.y(), br.width(), br.height(), br.x(), br.y()); - XFreeGC(display(), gc); - } - - - if (platformWindow->needsSync()) { - platformWindow->updateSyncRequestCounter(); - } else { - XFlush(display()); - } -} - -QImage QXcbNativeBackingStore::toImage() const -{ - return m_pixmap.toImage(); -} - -void QXcbNativeBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - if (size == m_pixmap.size()) - return; - - QPixmap newPixmap(size); - -#if QT_CONFIG(xrender) - if (m_translucentBackground && newPixmap.depth() != 32) - qt_x11Pixmap(newPixmap)->convertToARGB32(); -#endif - - if (!m_pixmap.isNull()) { - Pixmap from = qt_x11PixmapHandle(m_pixmap); - Pixmap to = qt_x11PixmapHandle(newPixmap); - QRect br = staticContents.boundingRect().intersected(QRect(QPoint(0, 0), size)); - - if (!br.isEmpty()) { - GC gc = XCreateGC(display(), to, 0, nullptr); - XCopyArea(display(), from, to, gc, br.x(), br.y(), br.width(), br.height(), br.x(), br.y()); - XFreeGC(display(), gc); - } - } - - m_pixmap = newPixmap; -} - -bool QXcbNativeBackingStore::scroll(const QRegion &area, int dx, int dy) -{ - if (m_pixmap.isNull()) - return false; - - QRect rect = area.boundingRect(); - Pixmap pix = qt_x11PixmapHandle(m_pixmap); - - GC gc = XCreateGC(display(), pix, 0, nullptr); - XCopyArea(display(), pix, pix, gc, - rect.x(), rect.y(), rect.width(), rect.height(), - rect.x()+dx, rect.y()+dy); - XFreeGC(display(), gc); - return true; -} - -void QXcbNativeBackingStore::beginPaint(const QRegion ®ion) -{ - QX11PlatformPixmap *x11pm = qt_x11Pixmap(m_pixmap); - if (x11pm) - x11pm->setIsBackingStore(true); - -#if QT_CONFIG(xrender) - if (m_translucentBackground) { - const QList<XRectangle> xrects = qt_region_to_xrectangles(region); - const XRenderColor color = { 0, 0, 0, 0 }; - XRenderFillRectangles(display(), PictOpSrc, - qt_x11PictureHandle(m_pixmap), &color, - xrects.constData(), xrects.size()); - } -#else - Q_UNUSED(region); -#endif -} - -Display *QXcbNativeBackingStore::display() const -{ - return static_cast<Display *>(static_cast<QXcbWindow *>(window()->handle())->connection()->xlib_display()); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h deleted file mode 100644 index b730b076d3f..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11_p.h +++ /dev/null @@ -1,38 +0,0 @@ -// 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 - -#pragma once - -#include <qpa/qplatformbackingstore.h> - -typedef struct _XDisplay Display; - -QT_BEGIN_NAMESPACE - -class QXcbWindow; - -class QXcbNativeBackingStore : public QPlatformBackingStore -{ -public: - QXcbNativeBackingStore(QWindow *window); - ~QXcbNativeBackingStore(); - - QPaintDevice *paintDevice() override; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override; - - QImage toImage() const override; - - void resize(const QSize &size, const QRegion &staticContents) override; - bool scroll(const QRegion &area, int dx, int dy) override; - - void beginPaint(const QRegion ®ion) override; - -private: - Display *display() const; - - QPixmap m_pixmap; - bool m_translucentBackground; -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp deleted file mode 100644 index fddd3e03989..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11.cpp +++ /dev/null @@ -1,615 +0,0 @@ -// 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 - -#include <QVarLengthArray> - -#include <private/qguiapplication_p.h> - -#include "qcolormap_x11_p.h" -#include "qxcbnativepainting.h" -#include "qt_x11_p.h" - -QT_BEGIN_NAMESPACE - -class QXcbColormapPrivate -{ -public: - QXcbColormapPrivate() - : ref(1), mode(QXcbColormap::Direct), depth(0), - colormap(0), defaultColormap(true), - visual(0), defaultVisual(true), - r_max(0), g_max(0), b_max(0), - r_shift(0), g_shift(0), b_shift(0) - {} - - QAtomicInt ref; - - QXcbColormap::Mode mode; - int depth; - - Colormap colormap; - bool defaultColormap; - - Visual *visual; - bool defaultVisual; - - int r_max; - int g_max; - int b_max; - - uint r_shift; - uint g_shift; - uint b_shift; - - QList<QColor> colors; - QList<int> pixels; -}; - -static uint right_align(uint v) -{ - while (!(v & 0x1)) - v >>= 1; - return v; -} - -static int cube_root(int v) -{ - if (v == 1) - return 1; - // brute force algorithm - int i = 1; - for (;;) { - const int b = i * i * i; - if (b <= v) { - ++i; - } else { - --i; - break; - } - } - return i; -} - -static Visual *find_visual(Display *display, - int screen, - int visual_class, - int visual_id, - int *depth, - bool *defaultVisual) -{ - XVisualInfo *vi, rvi; - int count; - - uint mask = VisualScreenMask; - rvi.screen = screen; - - if (visual_class != -1) { - rvi.c_class = visual_class; - mask |= VisualClassMask; - } - if (visual_id != -1) { - rvi.visualid = visual_id; - mask |= VisualIDMask; - } - - Visual *visual = DefaultVisual(display, screen); - *defaultVisual = true; - *depth = DefaultDepth(display, screen); - - vi = XGetVisualInfo(display, mask, &rvi, &count); - if (vi) { - int best = 0; - for (int x = 0; x < count; ++x) { - if (vi[x].depth > vi[best].depth) - best = x; - } - if (best >= 0 && best <= count && vi[best].visualid != XVisualIDFromVisual(visual)) { - visual = vi[best].visual; - *defaultVisual = (visual == DefaultVisual(display, screen)); - *depth = vi[best].depth; - } - } - if (vi) - XFree((char *)vi); - return visual; -} - -static void query_colormap(QXcbColormapPrivate *d, int screen) -{ - Display *display = X11->display; - - // query existing colormap - int q_colors = (((1u << d->depth) > 256u) ? 256u : (1u << d->depth)); - XColor queried[256]; - memset(queried, 0, sizeof(queried)); - for (int x = 0; x < q_colors; ++x) - queried[x].pixel = x; - XQueryColors(display, d->colormap, queried, q_colors); - - d->colors.resize(q_colors); - for (int x = 0; x < q_colors; ++x) { - if (queried[x].red == 0 - && queried[x].green == 0 - && queried[x].blue == 0 - && queried[x].pixel != BlackPixel(display, screen)) { - // unallocated color cell, skip it - continue; - } - - d->colors[x] = QColor::fromRgbF(queried[x].red / float(USHRT_MAX), - queried[x].green / float(USHRT_MAX), - queried[x].blue / float(USHRT_MAX)); - } - - // for missing colors, find the closest color in the existing colormap - Q_ASSERT(d->pixels.size()); - for (int x = 0; x < d->pixels.size(); ++x) { - if (d->pixels.at(x) != -1) - continue; - - QRgb rgb; - if (d->mode == QXcbColormap::Indexed) { - const int r = (x / (d->g_max * d->b_max)) % d->r_max; - const int g = (x / d->b_max) % d->g_max; - const int b = x % d->b_max; - rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1), - (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1), - (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1)); - } else { - rgb = qRgb(x, x, x); - } - - // find closest color - int mindist = INT_MAX, best = -1; - for (int y = 0; y < q_colors; ++y) { - int r = qRed(rgb) - (queried[y].red >> 8); - int g = qGreen(rgb) - (queried[y].green >> 8); - int b = qBlue(rgb) - (queried[y].blue >> 8); - int dist = (r * r) + (g * g) + (b * b); - if (dist < mindist) { - mindist = dist; - best = y; - } - } - - Q_ASSERT(best >= 0 && best < q_colors); - if (d->visual->c_class & 1) { - XColor xcolor; - xcolor.red = queried[best].red; - xcolor.green = queried[best].green; - xcolor.blue = queried[best].blue; - xcolor.pixel = queried[best].pixel; - - if (XAllocColor(display, d->colormap, &xcolor)) { - d->pixels[x] = xcolor.pixel; - } else { - // some weird stuff is going on... - d->pixels[x] = (qGray(rgb) < 127 - ? BlackPixel(display, screen) - : WhitePixel(display, screen)); - } - } else { - d->pixels[x] = best; - } - } -} - -static void init_gray(QXcbColormapPrivate *d, int screen) -{ - d->pixels.resize(d->r_max); - - for (int g = 0; g < d->g_max; ++g) { - const int gray = (g * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1); - const QRgb rgb = qRgb(gray, gray, gray); - - d->pixels[g] = -1; - - if (d->visual->c_class & 1) { - XColor xcolor; - xcolor.red = qRed(rgb) * 0x101; - xcolor.green = qGreen(rgb) * 0x101; - xcolor.blue = qBlue(rgb) * 0x101; - xcolor.pixel = 0ul; - - if (XAllocColor(X11->display, d->colormap, &xcolor)) - d->pixels[g] = xcolor.pixel; - } - } - - query_colormap(d, screen); -} - -static void init_indexed(QXcbColormapPrivate *d, int screen) -{ - d->pixels.resize(d->r_max * d->g_max * d->b_max); - - // create color cube - for (int x = 0, r = 0; r < d->r_max; ++r) { - for (int g = 0; g < d->g_max; ++g) { - for (int b = 0; b < d->b_max; ++b, ++x) { - const QRgb rgb = qRgb((r * 0xff + (d->r_max - 1) / 2) / (d->r_max - 1), - (g * 0xff + (d->g_max - 1) / 2) / (d->g_max - 1), - (b * 0xff + (d->b_max - 1) / 2) / (d->b_max - 1)); - - d->pixels[x] = -1; - - if (d->visual->c_class & 1) { - XColor xcolor; - xcolor.red = qRed(rgb) * 0x101; - xcolor.green = qGreen(rgb) * 0x101; - xcolor.blue = qBlue(rgb) * 0x101; - xcolor.pixel = 0ul; - - if (XAllocColor(X11->display, d->colormap, &xcolor)) - d->pixels[x] = xcolor.pixel; - } - } - } - } - - query_colormap(d, screen); -} - -static void init_direct(QXcbColormapPrivate *d, bool ownColormap) -{ - if (d->visual->c_class != DirectColor || !ownColormap) - return; - - // preallocate 768 on the stack, so that we don't have to malloc - // for the common case (<= 24 bpp) - QVarLengthArray<XColor, 768> colorTable(d->r_max + d->g_max + d->b_max); - int i = 0; - - for (int r = 0; r < d->r_max; ++r) { - colorTable[i].red = r << 8 | r; - colorTable[i].pixel = r << d->r_shift; - colorTable[i].flags = DoRed; - ++i; - } - - for (int g = 0; g < d->g_max; ++g) { - colorTable[i].green = g << 8 | g; - colorTable[i].pixel = g << d->g_shift; - colorTable[i].flags = DoGreen; - ++i; - } - - for (int b = 0; b < d->b_max; ++b) { - colorTable[i].blue = (b << 8 | b); - colorTable[i].pixel = b << d->b_shift; - colorTable[i].flags = DoBlue; - ++i; - } - - XStoreColors(X11->display, d->colormap, colorTable.data(), colorTable.count()); -} - -static QXcbColormap **cmaps = nullptr; - -void QXcbColormap::initialize() -{ - Display *display = X11->display; - const int screens = ScreenCount(display); - - cmaps = new QXcbColormap*[screens]; - - for (int i = 0; i < screens; ++i) { - cmaps[i] = new QXcbColormap; - QXcbColormapPrivate * const d = cmaps[i]->d; - - bool use_stdcmap = false; - int color_count = X11->color_count; - - // defaults - d->depth = DefaultDepth(display, i); - d->colormap = DefaultColormap(display, i); - d->defaultColormap = true; - d->visual = DefaultVisual(display, i); - d->defaultVisual = true; - - Visual *argbVisual = nullptr; - - if (X11->visual && i == DefaultScreen(display)) { - // only use the outside colormap on the default screen - d->visual = find_visual(display, i, X11->visual->c_class, - XVisualIDFromVisual(X11->visual), - &d->depth, &d->defaultVisual); - } else if ((X11->visual_class != -1 && X11->visual_class >= 0 && X11->visual_class < 6) - || (X11->visual_id != -1)) { - // look for a specific visual or type of visual - d->visual = find_visual(display, i, X11->visual_class, X11->visual_id, - &d->depth, &d->defaultVisual); - } else if (!X11->custom_cmap) { - XStandardColormap *stdcmap = nullptr; - int ncmaps = 0; - -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - int nvi; - XVisualInfo templ; - templ.screen = i; - templ.depth = 32; - templ.c_class = TrueColor; - XVisualInfo *xvi = XGetVisualInfo(X11->display, VisualScreenMask | - VisualDepthMask | - VisualClassMask, &templ, &nvi); - for (int idx = 0; idx < nvi; ++idx) { - XRenderPictFormat *format = XRenderFindVisualFormat(X11->display, - xvi[idx].visual); - if (format->type == PictTypeDirect && format->direct.alphaMask) { - argbVisual = xvi[idx].visual; - break; - } - } - XFree(xvi); - } -#endif - if (XGetRGBColormaps(display, RootWindow(display, i), - &stdcmap, &ncmaps, XA_RGB_DEFAULT_MAP)) { - if (stdcmap) { - for (int c = 0; c < ncmaps; ++c) { - if (!stdcmap[c].red_max || - !stdcmap[c].green_max || - !stdcmap[c].blue_max || - !stdcmap[c].red_mult || - !stdcmap[c].green_mult || - !stdcmap[c].blue_mult) - continue; // invalid stdcmap - - XVisualInfo proto; - proto.visualid = stdcmap[c].visualid; - proto.screen = i; - - int nvisuals = 0; - XVisualInfo *vi = XGetVisualInfo(display, VisualIDMask | VisualScreenMask, - &proto, &nvisuals); - if (vi) { - if (nvisuals > 0) { - use_stdcmap = true; - - d->mode = ((vi[0].visual->c_class < StaticColor) - ? Gray - : ((vi[0].visual->c_class < TrueColor) - ? Indexed - : Direct)); - - d->depth = vi[0].depth; - d->colormap = stdcmap[c].colormap; - d->defaultColormap = true; - d->visual = vi[0].visual; - d->defaultVisual = (d->visual == DefaultVisual(display, i)); - - d->r_max = stdcmap[c].red_max + 1; - d->g_max = stdcmap[c].green_max + 1; - d->b_max = stdcmap[c].blue_max + 1; - - if (d->mode == Direct) { - // calculate offsets - d->r_shift = lowest_bit(d->visual->red_mask); - d->g_shift = lowest_bit(d->visual->green_mask); - d->b_shift = lowest_bit(d->visual->blue_mask); - } else { - d->r_shift = 0; - d->g_shift = 0; - d->b_shift = 0; - } - } - XFree(vi); - } - break; - } - XFree(stdcmap); - } - } - } - if (!use_stdcmap) { - switch (d->visual->c_class) { - case StaticGray: - d->mode = Gray; - - d->r_max = d->g_max = d->b_max = d->visual->map_entries; - break; - - case XGrayScale: - d->mode = Gray; - - // follow precedent set in libXmu... - if (color_count != 0) - d->r_max = d->g_max = d->b_max = color_count; - else if (d->visual->map_entries > 65000) - d->r_max = d->g_max = d->b_max = 4096; - else if (d->visual->map_entries > 4000) - d->r_max = d->g_max = d->b_max = 512; - else if (d->visual->map_entries > 250) - d->r_max = d->g_max = d->b_max = 12; - else - d->r_max = d->g_max = d->b_max = 4; - break; - - case StaticColor: - d->mode = Indexed; - - d->r_max = right_align(d->visual->red_mask) + 1; - d->g_max = right_align(d->visual->green_mask) + 1; - d->b_max = right_align(d->visual->blue_mask) + 1; - break; - - case PseudoColor: - d->mode = Indexed; - - // follow precedent set in libXmu... - if (color_count != 0) - d->r_max = d->g_max = d->b_max = cube_root(color_count); - else if (d->visual->map_entries > 65000) - d->r_max = d->g_max = d->b_max = 27; - else if (d->visual->map_entries > 4000) - d->r_max = d->g_max = d->b_max = 12; - else if (d->visual->map_entries > 250) - d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries - 125); - else - d->r_max = d->g_max = d->b_max = cube_root(d->visual->map_entries); - break; - - case TrueColor: - case DirectColor: - d->mode = Direct; - - d->r_max = right_align(d->visual->red_mask) + 1; - d->g_max = right_align(d->visual->green_mask) + 1; - d->b_max = right_align(d->visual->blue_mask) + 1; - - d->r_shift = lowest_bit(d->visual->red_mask); - d->g_shift = lowest_bit(d->visual->green_mask); - d->b_shift = lowest_bit(d->visual->blue_mask); - break; - } - } - - bool ownColormap = false; - if (X11->colormap && i == DefaultScreen(display)) { - // only use the outside colormap on the default screen - d->colormap = X11->colormap; - d->defaultColormap = (d->colormap == DefaultColormap(display, i)); - } else if ((!use_stdcmap - && (((d->visual->c_class & 1) && X11->custom_cmap) - || d->visual != DefaultVisual(display, i))) - || d->visual->c_class == DirectColor) { - // allocate custom colormap (we always do this when using DirectColor visuals) - d->colormap = - XCreateColormap(display, RootWindow(display, i), d->visual, - d->visual->c_class == DirectColor ? AllocAll : AllocNone); - d->defaultColormap = false; - ownColormap = true; - } - - switch (d->mode) { - case Gray: - init_gray(d, i); - break; - case Indexed: - init_indexed(d, i); - break; - case Direct: - init_direct(d, ownColormap); - break; - } - - QX11InfoData *screen = X11->screens + i; - screen->depth = d->depth; - screen->visual = d->visual; - screen->defaultVisual = d->defaultVisual; - screen->colormap = d->colormap; - screen->defaultColormap = d->defaultColormap; - screen->cells = screen->visual->map_entries; - - if (argbVisual) { - X11->argbVisuals[i] = argbVisual; - X11->argbColormaps[i] = XCreateColormap(display, RootWindow(display, i), argbVisual, AllocNone); - } - - // ### - // We assume that 8bpp == pseudocolor, but this is not - // always the case (according to the X server), so we need - // to make sure that our internal data is setup in a way - // that is compatible with our assumptions - if (screen->visual->c_class == TrueColor && screen->depth == 8 && screen->cells == 8) - screen->cells = 256; - } -} - -void QXcbColormap::cleanup() -{ - Display *display = X11->display; - const int screens = ScreenCount(display); - - for (int i = 0; i < screens; ++i) - delete cmaps[i]; - - delete [] cmaps; - cmaps = 0; -} - - -QXcbColormap QXcbColormap::instance(int screen) -{ - if (screen == -1) - screen = QXcbX11Info::appScreen(); - return *cmaps[screen]; -} - -/*! \internal - Constructs a new colormap. -*/ -QXcbColormap::QXcbColormap() - : d(new QXcbColormapPrivate) -{} - -QXcbColormap::QXcbColormap(const QXcbColormap &colormap) - :d (colormap.d) -{ d->ref.ref(); } - -QXcbColormap::~QXcbColormap() -{ - if (!d->ref.deref()) { - if (!d->defaultColormap) - XFreeColormap(X11->display, d->colormap); - delete d; - } -} - -QXcbColormap::Mode QXcbColormap::mode() const -{ return d->mode; } - -int QXcbColormap::depth() const -{ return d->depth; } - -int QXcbColormap::size() const -{ - return (d->mode == Gray - ? d->r_max - : (d->mode == Indexed - ? d->r_max * d->g_max * d->b_max - : -1)); -} - -uint QXcbColormap::pixel(const QColor &color) const -{ - const QRgba64 rgba64 = color.rgba64(); - // XXX We emulate the raster engine here by getting the - // 8-bit values, but we could instead use the 16-bit - // values for slightly better color accuracy - const uint r = (rgba64.red8() * d->r_max) >> 8; - const uint g = (rgba64.green8() * d->g_max) >> 8; - const uint b = (rgba64.blue8() * d->b_max) >> 8; - if (d->mode != Direct) { - if (d->mode == Gray) - return d->pixels.at((r * 30 + g * 59 + b * 11) / 100); - return d->pixels.at(r * d->g_max * d->b_max + g * d->b_max + b); - } - return (r << d->r_shift) + (g << d->g_shift) + (b << d->b_shift); -} - -const QColor QXcbColormap::colorAt(uint pixel) const -{ - if (d->mode != Direct) { - Q_ASSERT(pixel <= (uint)d->colors.size()); - return d->colors.at(pixel); - } - - const int r = (((pixel & d->visual->red_mask) >> d->r_shift) << 8) / d->r_max; - const int g = (((pixel & d->visual->green_mask) >> d->g_shift) << 8) / d->g_max; - const int b = (((pixel & d->visual->blue_mask) >> d->b_shift) << 8) / d->b_max; - return QColor(r, g, b); -} - -const QList<QColor> QXcbColormap::colormap() const -{ return d->colors; } - -QXcbColormap &QXcbColormap::operator=(const QXcbColormap &colormap) -{ - qAtomicAssign(d, colormap.d); - return *this; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h deleted file mode 100644 index 9c9cce424c9..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qcolormap_x11_p.h +++ /dev/null @@ -1,43 +0,0 @@ -// 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 - -#pragma once - -#include <QColor> -#include <QList> - -QT_BEGIN_NAMESPACE - -class QXcbColormapPrivate; -class QXcbColormap -{ -public: - enum Mode { Direct, Indexed, Gray }; - - static void initialize(); - static void cleanup(); - - static QXcbColormap instance(int screen = -1); - - QXcbColormap(const QXcbColormap &colormap); - ~QXcbColormap(); - - QXcbColormap &operator=(const QXcbColormap &colormap); - - Mode mode() const; - - int depth() const; - int size() const; - - uint pixel(const QColor &color) const; - const QColor colorAt(uint pixel) const; - - const QList<QColor> colormap() const; - -private: - QXcbColormap(); - QXcbColormapPrivate *d; -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp deleted file mode 100644 index 2f3827025f3..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp +++ /dev/null @@ -1,2807 +0,0 @@ -// 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 - -#include <QtCore/qrandom.h> - -#include <private/qpixmapcache_p.h> -#include <private/qpaintengine_p.h> -#include <private/qpainterpath_p.h> -#include <private/qdrawhelper_p.h> -#include <private/qfontengineglyphcache_p.h> - -#if QT_CONFIG(fontconfig) -#include <private/qfontengine_ft_p.h> -#endif - -#include "qpaintengine_x11_p.h" -#include "qpolygonclipper_p.h" -#include "qtessellator_p.h" -#include "qpixmap_x11_p.h" -#include "qcolormap_x11_p.h" -#include "qt_x11_p.h" -#include "qxcbexport.h" -#include "qxcbnativepainting.h" - -QT_BEGIN_NAMESPACE - -using namespace Qt::StringLiterals; - -#if QT_CONFIG(xrender) - -class QXRenderTessellator : public QTessellator -{ -public: - QXRenderTessellator() : traps(0), allocated(0), size(0) {} - ~QXRenderTessellator() { free(traps); } - XTrapezoid *traps; - int allocated; - int size; - void addTrap(const Trapezoid &trap) override; - QRect tessellate(const QPointF *points, int nPoints, bool winding) { - size = 0; - setWinding(winding); - return QTessellator::tessellate(points, nPoints).toRect(); - } - void done() { - if (allocated > 64) { - free(traps); - traps = 0; - allocated = 0; - } - } -}; - -void QXRenderTessellator::addTrap(const Trapezoid &trap) -{ - if (size == allocated) { - allocated = qMax(2*allocated, 64); - traps = q_check_ptr((XTrapezoid *)realloc(traps, allocated * sizeof(XTrapezoid))); - } - traps[size].top = Q27Dot5ToXFixed(trap.top); - traps[size].bottom = Q27Dot5ToXFixed(trap.bottom); - traps[size].left.p1.x = Q27Dot5ToXFixed(trap.topLeft->x); - traps[size].left.p1.y = Q27Dot5ToXFixed(trap.topLeft->y); - traps[size].left.p2.x = Q27Dot5ToXFixed(trap.bottomLeft->x); - traps[size].left.p2.y = Q27Dot5ToXFixed(trap.bottomLeft->y); - traps[size].right.p1.x = Q27Dot5ToXFixed(trap.topRight->x); - traps[size].right.p1.y = Q27Dot5ToXFixed(trap.topRight->y); - traps[size].right.p2.x = Q27Dot5ToXFixed(trap.bottomRight->x); - traps[size].right.p2.y = Q27Dot5ToXFixed(trap.bottomRight->y); - ++size; -} - -#endif // QT_CONFIG(xrender) - -class QX11PaintEnginePrivate : public QPaintEnginePrivate -{ - Q_DECLARE_PUBLIC(QX11PaintEngine) -public: - QX11PaintEnginePrivate() - { - opacity = 1.0; - scrn = -1; - hd = 0; - picture = 0; - gc = gc_brush = 0; - dpy = 0; - xinfo = 0; - txop = QTransform::TxNone; - has_clipping = false; - render_hints = 0; - xform_scale = 1; -#if QT_CONFIG(xrender) - tessellator = 0; -#endif - } - enum GCMode { - PenGC, - BrushGC - }; - - void init(); - void fillPolygon_translated(const QPointF *points, int pointCount, GCMode gcMode, - QPaintEngine::PolygonDrawMode mode); - void fillPolygon_dev(const QPointF *points, int pointCount, GCMode gcMode, - QPaintEngine::PolygonDrawMode mode); - void fillPath(const QPainterPath &path, GCMode gcmode, bool transform); - void strokePolygon_dev(const QPointF *points, int pointCount, bool close); - void strokePolygon_translated(const QPointF *points, int pointCount, bool close); - void setupAdaptedOrigin(const QPoint &p); - void resetAdaptedOrigin(); - void decidePathFallback() { - use_path_fallback = has_alpha_brush - || has_alpha_pen - || has_custom_pen - || has_complex_xform - || (render_hints & QPainter::Antialiasing); - } - void decideCoordAdjust() { - adjust_coords = false; - } - void clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly); - void systemStateChanged() override; - inline bool isCosmeticPen() const { - return cpen.isCosmetic(); - } - - Display *dpy; - int scrn; - int pdev_depth; - unsigned long hd; - QPixmap brush_pm; -#if QT_CONFIG(xrender) - unsigned long picture; - unsigned long current_brush; - QPixmap bitmap_texture; - int composition_mode; -#else - unsigned long picture; -#endif - GC gc; - GC gc_brush; - - QPen cpen; - QBrush cbrush; - QRegion crgn; - QTransform matrix; - qreal opacity; - - uint has_complex_xform : 1; - uint has_scaling_xform : 1; - uint has_non_scaling_xform : 1; - uint has_custom_pen : 1; - uint use_path_fallback : 1; - uint adjust_coords : 1; - uint has_clipping : 1; - uint adapted_brush_origin : 1; - uint adapted_pen_origin : 1; - uint has_pen : 1; - uint has_brush : 1; - uint has_texture : 1; - uint has_alpha_texture : 1; - uint has_pattern : 1; - uint has_alpha_pen : 1; - uint has_alpha_brush : 1; - uint use_sysclip : 1; - uint render_hints; - - const QXcbX11Info *xinfo; - QPointF bg_origin; - QTransform::TransformationType txop; - qreal xform_scale; - - struct qt_float_point - { - qreal x, y; - }; - QPolygonClipper<qt_float_point, qt_float_point, float> polygonClipper; - - int xlibMaxLinePoints; -#if QT_CONFIG(xrender) - QXRenderTessellator *tessellator; -#endif -}; - -#if QT_CONFIG(xrender) -class QXRenderGlyphCache : public QFontEngineGlyphCache -{ -public: - QXRenderGlyphCache(QXcbX11Info x, QFontEngine::GlyphFormat format, const QTransform &matrix); - ~QXRenderGlyphCache(); - - bool addGlyphs(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &positions); - bool draw(Drawable src, Drawable dst, const QTransform &matrix, const QTextItemInt &ti); - - inline GlyphSet glyphSet(); - inline int glyphBufferSize(const QFontEngineFT::Glyph &glyph) const; - - inline QImage::Format imageFormat() const; - inline const XRenderPictFormat *renderPictFormat() const; - - static inline QFontEngine::GlyphFormat glyphFormatForDepth(QFontEngine *fontEngine, int depth); - static inline Glyph glyphId(glyph_t glyph, QFixed subPixelPosition); - - static inline bool isValidCoordinate(const QFixedPoint &fp); - -private: - QXcbX11Info xinfo; - GlyphSet gset; - QSet<Glyph> cachedGlyphs; -}; -#endif // QT_CONFIG(xrender) - -extern QPixmap qt_pixmapForBrush(int brushStyle, bool invert); //in qbrush.cpp -extern QPixmap qt_toX11Pixmap(const QPixmap &pixmap); - -extern "C" { -Q_XCB_EXPORT Drawable qt_x11Handle(const QPaintDevice *pd) -{ - if (!pd) - return 0; - -// if (pd->devType() == QInternal::Widget) -// return static_cast<const QWidget *>(pd)->handle(); - - if (pd->devType() == QInternal::Pixmap) - return qt_x11PixmapHandle(*static_cast<const QPixmap *>(pd)); - - return 0; -} -} - -static const QXcbX11Info *qt_x11Info(const QPaintDevice *pd) -{ - if (!pd) - return 0; - -// if (pd->devType() == QInternal::Widget) -// return &static_cast<const QWidget *>(pd)->x11Info(); - - if (pd->devType() == QInternal::Pixmap) - return &qt_x11Info(*static_cast<const QPixmap *>(pd)); - - return 0; -} - -// use the same rounding as in qrasterizer.cpp (6 bit fixed point) -static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; - -#undef X11 // defined in qt_x11_p.h -extern "C" { -/*! - Returns the X11 specific pen GC for the painter \a p. Note that - QPainter::begin() must be called before this function returns a - valid GC. -*/ -GC Q_XCB_EXPORT qt_x11_get_pen_gc(QPainter *p) -{ - if (p && p->paintEngine() - && p->paintEngine()->isActive() - && p->paintEngine()->type() == QPaintEngine::X11) { - return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc; - } - return 0; -} - -/*! - Returns the X11 specific brush GC for the painter \a p. Note that - QPainter::begin() must be called before this function returns a - valid GC. -*/ -GC Q_XCB_EXPORT qt_x11_get_brush_gc(QPainter *p) -{ - if (p && p->paintEngine() - && p->paintEngine()->isActive() - && p->paintEngine()->type() == QPaintEngine::X11) { - return static_cast<QX11PaintEngine *>(p->paintEngine())->d_func()->gc_brush; - } - return 0; -} -} -#define X11 qt_x11Data - -// internal helper. Converts an integer value to an unique string token -template <typename T> - struct HexString -{ - inline HexString(const T t) - : val(t) - {} - - inline void write(QChar *&dest) const - { - const ushort hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - const char *c = reinterpret_cast<const char *>(&val); - for (uint i = 0; i < sizeof(T); ++i) { - *dest++ = hexChars[*c & 0xf]; - *dest++ = hexChars[(*c & 0xf0) >> 4]; - ++c; - } - } - const T val; -}; - -// specialization to enable fast concatenating of our string tokens to a string -template <typename T> - struct QConcatenable<HexString<T> > -{ - typedef HexString<T> type; - enum { ExactSize = true }; - static int size(const HexString<T> &) { return sizeof(T) * 2; } - static inline void appendTo(const HexString<T> &str, QChar *&out) { str.write(out); } - typedef QString ConvertTo; -}; - -#if QT_CONFIG(xrender) -static const int compositionModeToRenderOp[QPainter::CompositionMode_Xor + 1] = { - PictOpOver, //CompositionMode_SourceOver, - PictOpOverReverse, //CompositionMode_DestinationOver, - PictOpClear, //CompositionMode_Clear, - PictOpSrc, //CompositionMode_Source, - PictOpDst, //CompositionMode_Destination, - PictOpIn, //CompositionMode_SourceIn, - PictOpInReverse, //CompositionMode_DestinationIn, - PictOpOut, //CompositionMode_SourceOut, - PictOpOutReverse, //CompositionMode_DestinationOut, - PictOpAtop, //CompositionMode_SourceAtop, - PictOpAtopReverse, //CompositionMode_DestinationAtop, - PictOpXor //CompositionMode_Xor -}; - -static inline int qpainterOpToXrender(QPainter::CompositionMode mode) -{ - Q_ASSERT(mode <= QPainter::CompositionMode_Xor); - return compositionModeToRenderOp[mode]; -} - -static inline bool complexPictOp(int op) -{ - return op != PictOpOver && op != PictOpSrc; -} -#endif - -static inline void x11SetClipRegion(Display *dpy, GC gc, GC gc2, -#if QT_CONFIG(xrender) - Picture picture, -#else - Qt::HANDLE picture, -#endif - const QRegion &r) -{ -// int num; -// XRectangle *rects = (XRectangle *)qt_getClipRects(r, num); - QList<XRectangle> rects = qt_region_to_xrectangles(r); - int num = rects.size(); - - if (gc) - XSetClipRectangles( dpy, gc, 0, 0, rects.data(), num, Unsorted ); - if (gc2) - XSetClipRectangles( dpy, gc2, 0, 0, rects.data(), num, Unsorted ); - -#if QT_CONFIG(xrender) - if (picture) - XRenderSetPictureClipRectangles(dpy, picture, 0, 0, rects.data(), num); -#else - Q_UNUSED(picture); -#endif // QT_CONFIG(xrender) -} - - -static inline void x11ClearClipRegion(Display *dpy, GC gc, GC gc2, -#if QT_CONFIG(xrender) - Picture picture -#else - Qt::HANDLE picture -#endif - ) -{ - if (gc) - XSetClipMask(dpy, gc, XNone); - if (gc2) - XSetClipMask(dpy, gc2, XNone); - -#if QT_CONFIG(xrender) - if (picture) { - XRenderPictureAttributes attrs; - attrs.clip_mask = XNone; - XRenderChangePicture (dpy, picture, CPClipMask, &attrs); - } -#else - Q_UNUSED(picture); -#endif // QT_CONFIG(xrender) -} - - -#define DITHER_SIZE 16 -static const uchar base_dither_matrix[DITHER_SIZE][DITHER_SIZE] = { - { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, - { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, - { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, - { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, - { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 }, - { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, - { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, - { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, - { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 }, - { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, - { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, - { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, - { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 }, - { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, - { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, - { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } -}; - -static QPixmap qt_patternForAlpha(uchar alpha, int screen) -{ - QPixmap pm; - QString key = "$qt-alpha-brush$"_L1 - % HexString<uchar>(alpha) - % HexString<int>(screen); - - if (!QPixmapCache::find(key, &pm)) { - // #### why not use a mono image here???? - QImage pattern(DITHER_SIZE, DITHER_SIZE, QImage::Format_ARGB32); - pattern.fill(0xffffffff); - for (int y = 0; y < DITHER_SIZE; ++y) { - for (int x = 0; x < DITHER_SIZE; ++x) { - if (base_dither_matrix[x][y] <= alpha) - pattern.setPixel(x, y, 0x00000000); - } - } - pm = QBitmap::fromImage(pattern); - qt_x11SetScreen(pm, screen); - //pm.x11SetScreen(screen); - QPixmapCache::insert(key, pm); - } - return pm; -} - - -#if QT_CONFIG(xrender) -static Picture getPatternFill(int screen, const QBrush &b) -{ - if (!X11->use_xrender) - return XNone; - - XRenderColor color = X11->preMultiply(b.color()); - XRenderColor bg_color; - - bg_color = X11->preMultiply(QColor(0, 0, 0, 0)); - - for (int i = 0; i < X11->pattern_fill_count; ++i) { - if (X11->pattern_fills[i].screen == screen - && X11->pattern_fills[i].opaque == false - && X11->pattern_fills[i].style == b.style() - && X11->pattern_fills[i].color.alpha == color.alpha - && X11->pattern_fills[i].color.red == color.red - && X11->pattern_fills[i].color.green == color.green - && X11->pattern_fills[i].color.blue == color.blue - && X11->pattern_fills[i].bg_color.alpha == bg_color.alpha - && X11->pattern_fills[i].bg_color.red == bg_color.red - && X11->pattern_fills[i].bg_color.green == bg_color.green - && X11->pattern_fills[i].bg_color.blue == bg_color.blue) - return X11->pattern_fills[i].picture; - } - // none found, replace one - int i = QRandomGenerator::global()->generate() % 16; - - if (X11->pattern_fills[i].screen != screen && X11->pattern_fills[i].picture) { - XRenderFreePicture (QXcbX11Info::display(), X11->pattern_fills[i].picture); - X11->pattern_fills[i].picture = 0; - } - - if (!X11->pattern_fills[i].picture) { - Pixmap pixmap = XCreatePixmap (QXcbX11Info::display(), RootWindow (QXcbX11Info::display(), screen), 8, 8, 32); - XRenderPictureAttributes attrs; - attrs.repeat = True; - X11->pattern_fills[i].picture = XRenderCreatePicture (QXcbX11Info::display(), pixmap, - XRenderFindStandardFormat(QXcbX11Info::display(), PictStandardARGB32), - CPRepeat, &attrs); - XFreePixmap (QXcbX11Info::display(), pixmap); - } - - X11->pattern_fills[i].screen = screen; - X11->pattern_fills[i].color = color; - X11->pattern_fills[i].bg_color = bg_color; - X11->pattern_fills[i].opaque = false; - X11->pattern_fills[i].style = b.style(); - - XRenderFillRectangle(QXcbX11Info::display(), PictOpSrc, X11->pattern_fills[i].picture, &bg_color, 0, 0, 8, 8); - - QPixmap pattern(qt_pixmapForBrush(b.style(), true)); - XRenderPictureAttributes attrs; - attrs.repeat = true; - XRenderChangePicture(QXcbX11Info::display(), qt_x11PictureHandle(pattern), CPRepeat, &attrs); - - Picture fill_fg = X11->getSolidFill(screen, b.color()); - XRenderComposite(QXcbX11Info::display(), PictOpOver, fill_fg, qt_x11PictureHandle(pattern), - X11->pattern_fills[i].picture, - 0, 0, 0, 0, 0, 0, 8, 8); - - return X11->pattern_fills[i].picture; -} - -static void qt_render_bitmap(Display *dpy, int scrn, Picture src, Picture dst, - int sx, int sy, int x, int y, int sw, int sh, - const QPen &pen) -{ - Picture fill_fg = X11->getSolidFill(scrn, pen.color()); - XRenderComposite(dpy, PictOpOver, - fill_fg, src, dst, sx, sy, sx, sy, x, y, sw, sh); -} -#endif - -void QX11PaintEnginePrivate::init() -{ - dpy = 0; - scrn = 0; - hd = 0; - picture = 0; - xinfo = 0; -#if QT_CONFIG(xrender) - current_brush = 0; - composition_mode = PictOpOver; - tessellator = new QXRenderTessellator; -#endif -} - -void QX11PaintEnginePrivate::setupAdaptedOrigin(const QPoint &p) -{ - if (adapted_pen_origin) - XSetTSOrigin(dpy, gc, p.x(), p.y()); - if (adapted_brush_origin) - XSetTSOrigin(dpy, gc_brush, p.x(), p.y()); -} - -void QX11PaintEnginePrivate::resetAdaptedOrigin() -{ - if (adapted_pen_origin) - XSetTSOrigin(dpy, gc, 0, 0); - if (adapted_brush_origin) - XSetTSOrigin(dpy, gc_brush, 0, 0); -} - -void QX11PaintEnginePrivate::clipPolygon_dev(const QPolygonF &poly, QPolygonF *clipped_poly) -{ - int clipped_count = 0; - qt_float_point *clipped_points = 0; - polygonClipper.clipPolygon((qt_float_point *) poly.data(), poly.size(), - &clipped_points, &clipped_count); - clipped_poly->resize(clipped_count); - for (int i=0; i<clipped_count; ++i) - (*clipped_poly)[i] = *((QPointF *)(&clipped_points[i])); -} - -void QX11PaintEnginePrivate::systemStateChanged() -{ - Q_Q(QX11PaintEngine); - QPainter *painter = q->state ? q->state->painter() : nullptr; - if (painter && painter->hasClipping()) { - if (q->testDirty(QPaintEngine::DirtyTransform)) - q->updateMatrix(q->state->transform()); - QPolygonF clip_poly_dev(matrix.map(painter->clipPath().toFillPolygon())); - QPolygonF clipped_poly_dev; - clipPolygon_dev(clip_poly_dev, &clipped_poly_dev); - q->updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip); - } else { - q->updateClipRegion_dev(QRegion(), Qt::NoClip); - } -} - -static QPaintEngine::PaintEngineFeatures qt_decide_features() -{ - QPaintEngine::PaintEngineFeatures features = - QPaintEngine::PrimitiveTransform - | QPaintEngine::PatternBrush - | QPaintEngine::AlphaBlend - | QPaintEngine::PainterPaths - | QPaintEngine::RasterOpModes; - - if (X11->use_xrender) { - features |= QPaintEngine::Antialiasing; - features |= QPaintEngine::PorterDuff; - features |= QPaintEngine::MaskedBrush; -#if 0 - if (X11->xrender_version > 10) { - features |= QPaintEngine::LinearGradientFill; - // ### - } -#endif - } - - return features; -} - -/* - * QX11PaintEngine members - */ - -QX11PaintEngine::QX11PaintEngine() - : QPaintEngine(*(new QX11PaintEnginePrivate), qt_decide_features()) -{ - Q_D(QX11PaintEngine); - d->init(); -} - -QX11PaintEngine::QX11PaintEngine(QX11PaintEnginePrivate &dptr) - : QPaintEngine(dptr, qt_decide_features()) -{ - Q_D(QX11PaintEngine); - d->init(); -} - -QX11PaintEngine::~QX11PaintEngine() -{ -#if QT_CONFIG(xrender) - Q_D(QX11PaintEngine); - delete d->tessellator; -#endif -} - -bool QX11PaintEngine::begin(QPaintDevice *pdev) -{ - Q_D(QX11PaintEngine); - d->xinfo = qt_x11Info(pdev); -#if QT_CONFIG(xrender) - if (pdev->devType() == QInternal::Pixmap) { - const QPixmap *pm = static_cast<const QPixmap *>(pdev); - QX11PlatformPixmap *data = static_cast<QX11PlatformPixmap*>(pm->handle()); - if (X11->use_xrender && data->depth() != 32 && data->x11_mask) - data->convertToARGB32(); - d->picture = qt_x11PictureHandle(*static_cast<const QPixmap *>(pdev)); - } -#else - d->picture = 0; -#endif - d->hd = qt_x11Handle(pdev); - - Q_ASSERT(d->xinfo != 0); - d->dpy = d->xinfo->display(); // get display variable - d->scrn = d->xinfo->screen(); // get screen variable - - d->crgn = QRegion(); - d->gc = XCreateGC(d->dpy, d->hd, 0, 0); - d->gc_brush = XCreateGC(d->dpy, d->hd, 0, 0); - d->has_alpha_brush = false; - d->has_alpha_pen = false; - d->has_clipping = false; - d->has_complex_xform = false; - d->has_scaling_xform = false; - d->has_non_scaling_xform = true; - d->xform_scale = 1; - d->has_custom_pen = false; - d->matrix = QTransform(); - d->pdev_depth = d->pdev->depth(); - d->render_hints = 0; - d->txop = QTransform::TxNone; - d->use_path_fallback = false; -#if QT_CONFIG(xrender) - d->composition_mode = PictOpOver; -#endif - d->xlibMaxLinePoints = 32762; // a safe number used to avoid, call to XMaxRequestSize(d->dpy) - 3; - d->opacity = 1; - - QX11PlatformPixmap *x11pm = paintDevice()->devType() == QInternal::Pixmap ? qt_x11Pixmap(*static_cast<QPixmap *>(paintDevice())) : nullptr; - d->use_sysclip = paintDevice()->devType() == QInternal::Widget || (x11pm ? x11pm->isBackingStore() : false); - - // Set up the polygon clipper. Note: This will only work in - // polyline mode as long as we have a buffer zone, since a - // polyline may be clipped into several non-connected polylines. - const int BUFFERZONE = 1000; - QRect devClipRect(-BUFFERZONE, -BUFFERZONE, - pdev->width() + 2*BUFFERZONE, pdev->height() + 2*BUFFERZONE); - d->polygonClipper.setBoundingRect(devClipRect); - - setSystemClip(systemClip()); - d->systemStateChanged(); - - qt_x11SetDefaultScreen(d->xinfo->screen()); - - updatePen(QPen(Qt::black)); - updateBrush(QBrush(Qt::white), QPoint()); - - setDirty(QPaintEngine::DirtyClipRegion); - setDirty(QPaintEngine::DirtyPen); - setDirty(QPaintEngine::DirtyBrush); - setDirty(QPaintEngine::DirtyBackground); - - setActive(true); - return true; -} - -bool QX11PaintEngine::end() -{ - Q_D(QX11PaintEngine); - -#if QT_CONFIG(xrender) - if (d->picture) { - // reset clipping/subwindow mode on our render picture - XRenderPictureAttributes attrs; - attrs.subwindow_mode = ClipByChildren; - attrs.clip_mask = XNone; - XRenderChangePicture(d->dpy, d->picture, CPClipMask|CPSubwindowMode, &attrs); - } -#endif - - if (d->gc_brush && d->pdev->painters < 2) { - XFreeGC(d->dpy, d->gc_brush); - d->gc_brush = 0; - } - - if (d->gc && d->pdev->painters < 2) { - XFreeGC(d->dpy, d->gc); - d->gc = 0; - } - - // Restore system clip for alien widgets painting outside the paint event. -// if (d->pdev->devType() == QInternal::Widget && !static_cast<QWidget *>(d->pdev)->internalWinId()) - d->currentClipDevice = nullptr; - setSystemClip(QRegion()); - - setActive(false); - return true; -} - -static bool clipLine(QLineF *line, const QRect &rect) -{ - qreal x1 = line->x1(); - qreal x2 = line->x2(); - qreal y1 = line->y1(); - qreal y2 = line->y2(); - - qreal left = rect.x(); - qreal right = rect.x() + rect.width() - 1; - qreal top = rect.y(); - qreal bottom = rect.y() + rect.height() - 1; - - enum { Left, Right, Top, Bottom }; - // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html - int p1 = ((x1 < left) << Left) - | ((x1 > right) << Right) - | ((y1 < top) << Top) - | ((y1 > bottom) << Bottom); - int p2 = ((x2 < left) << Left) - | ((x2 > right) << Right) - | ((y2 < top) << Top) - | ((y2 > bottom) << Bottom); - - if (p1 & p2) - // completely outside - return false; - - if (p1 | p2) { - qreal dx = x2 - x1; - qreal dy = y2 - y1; - - // clip x coordinates - if (x1 < left) { - y1 += dy/dx * (left - x1); - x1 = left; - } else if (x1 > right) { - y1 -= dy/dx * (x1 - right); - x1 = right; - } - if (x2 < left) { - y2 += dy/dx * (left - x2); - x2 = left; - } else if (x2 > right) { - y2 -= dy/dx * (x2 - right); - x2 = right; - } - p1 = ((y1 < top) << Top) - | ((y1 > bottom) << Bottom); - p2 = ((y2 < top) << Top) - | ((y2 > bottom) << Bottom); - if (p1 & p2) - return false; - // clip y coordinates - if (y1 < top) { - x1 += dx/dy * (top - y1); - y1 = top; - } else if (y1 > bottom) { - x1 -= dx/dy * (y1 - bottom); - y1 = bottom; - } - if (y2 < top) { - x2 += dx/dy * (top - y2); - y2 = top; - } else if (y2 > bottom) { - x2 -= dx/dy * (y2 - bottom); - y2 = bottom; - } - *line = QLineF(QPointF(x1, y1), QPointF(x2, y2)); - } - return true; -} - -void QX11PaintEngine::drawLines(const QLine *lines, int lineCount) -{ - Q_ASSERT(lines); - Q_ASSERT(lineCount); - Q_D(QX11PaintEngine); - - if (d->has_alpha_brush - || d->has_alpha_pen - || d->has_custom_pen - || (d->cpen.widthF() > 0 && d->has_complex_xform - && !d->has_non_scaling_xform) - || (d->render_hints & QPainter::Antialiasing)) { - for (int i = 0; i < lineCount; ++i) { - QPainterPath path(lines[i].p1()); - path.lineTo(lines[i].p2()); - drawPath(path); - } - return; - } - - if (d->has_pen) { - for (int i = 0; i < lineCount; ++i) { - QLineF linef; - if (d->txop == QTransform::TxNone) { - linef = lines[i]; - } else { - linef = d->matrix.map(QLineF(lines[i])); - } - if (clipLine(&linef, d->polygonClipper.boundingRect())) { - int x1 = qRound(linef.x1() + aliasedCoordinateDelta); - int y1 = qRound(linef.y1() + aliasedCoordinateDelta); - int x2 = qRound(linef.x2() + aliasedCoordinateDelta); - int y2 = qRound(linef.y2() + aliasedCoordinateDelta); - - XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2); - } - } - } -} - -void QX11PaintEngine::drawLines(const QLineF *lines, int lineCount) -{ - Q_ASSERT(lines); - Q_ASSERT(lineCount); - Q_D(QX11PaintEngine); - - if (d->has_alpha_brush - || d->has_alpha_pen - || d->has_custom_pen - || (d->cpen.widthF() > 0 && d->has_complex_xform - && !d->has_non_scaling_xform) - || (d->render_hints & QPainter::Antialiasing)) { - for (int i = 0; i < lineCount; ++i) { - QPainterPath path(lines[i].p1()); - path.lineTo(lines[i].p2()); - drawPath(path); - } - return; - } - - if (d->has_pen) { - for (int i = 0; i < lineCount; ++i) { - QLineF linef = d->matrix.map(lines[i]); - if (clipLine(&linef, d->polygonClipper.boundingRect())) { - int x1 = qRound(linef.x1() + aliasedCoordinateDelta); - int y1 = qRound(linef.y1() + aliasedCoordinateDelta); - int x2 = qRound(linef.x2() + aliasedCoordinateDelta); - int y2 = qRound(linef.y2() + aliasedCoordinateDelta); - - XDrawLine(d->dpy, d->hd, d->gc, x1, y1, x2, y2); - } - } - } -} - -static inline QLine clipStraightLine(const QRect &clip, const QLine &l) -{ - if (l.p1().x() == l.p2().x()) { - int x = qBound(clip.left(), l.p1().x(), clip.right()); - int y1 = qBound(clip.top(), l.p1().y(), clip.bottom()); - int y2 = qBound(clip.top(), l.p2().y(), clip.bottom()); - - return QLine(x, y1, x, y2); - } else { - Q_ASSERT(l.p1().y() == l.p2().y()); - - int x1 = qBound(clip.left(), l.p1().x(), clip.right()); - int x2 = qBound(clip.left(), l.p2().x(), clip.right()); - int y = qBound(clip.top(), l.p1().y(), clip.bottom()); - - return QLine(x1, y, x2, y); - } -} - -void QX11PaintEngine::drawRects(const QRectF *rects, int rectCount) -{ - Q_D(QX11PaintEngine); - Q_ASSERT(rects); - Q_ASSERT(rectCount); - - if (rectCount != 1 - || d->has_pen - || d->has_alpha_brush - || d->has_complex_xform - || d->has_custom_pen - || d->cbrush.style() != Qt::SolidPattern -#if QT_CONFIG(xrender) - || complexPictOp(d->composition_mode) -#endif - ) - { - QPaintEngine::drawRects(rects, rectCount); - return; - } - - QPoint alignedOffset; - if (d->txop == QTransform::TxTranslate) { - QPointF offset(d->matrix.dx(), d->matrix.dy()); - alignedOffset = offset.toPoint(); - if (offset != QPointF(alignedOffset)) { - QPaintEngine::drawRects(rects, rectCount); - return; - } - } - - const QRectF& r = rects[0]; - QRect alignedRect = r.toAlignedRect(); - if (r != QRectF(alignedRect)) { - QPaintEngine::drawRects(rects, rectCount); - return; - } - alignedRect.translate(alignedOffset); - - QRect clip(d->polygonClipper.boundingRect()); - alignedRect = alignedRect.intersected(clip); - if (alignedRect.isEmpty()) - return; - - // simple-case: - // the rectangle is pixel-aligned - // the fill brush is just a solid non-alpha color - // the painter transform is only integer translation - // ignore: antialiasing and just XFillRectangles directly - XRectangle xrect; - xrect.x = short(alignedRect.x()); - xrect.y = short(alignedRect.y()); - xrect.width = ushort(alignedRect.width()); - xrect.height = ushort(alignedRect.height()); - XFillRectangles(d->dpy, d->hd, d->gc_brush, &xrect, 1); -} - -void QX11PaintEngine::drawRects(const QRect *rects, int rectCount) -{ - Q_D(QX11PaintEngine); - Q_ASSERT(rects); - Q_ASSERT(rectCount); - - if (d->has_alpha_pen - || d->has_complex_xform - || d->has_custom_pen - || (d->render_hints & QPainter::Antialiasing)) - { - for (int i = 0; i < rectCount; ++i) { - QPainterPath path; - path.addRect(rects[i]); - drawPath(path); - } - return; - } - - QRect clip(d->polygonClipper.boundingRect()); - QPoint offset(qRound(d->matrix.dx()), qRound(d->matrix.dy())); -#if QT_CONFIG(xrender) - ::Picture pict = d->picture; - - if (X11->use_xrender && pict && d->has_brush && d->pdev_depth != 1 - && (d->has_texture || d->has_alpha_brush || complexPictOp(d->composition_mode))) - { - XRenderColor xc; - if (!d->has_texture && !d->has_pattern) - xc = X11->preMultiply(d->cbrush.color()); - - for (int i = 0; i < rectCount; ++i) { - QRect r(rects[i]); - if (d->txop == QTransform::TxTranslate) - r.translate(offset); - - if (r.width() == 0 || r.height() == 0) { - if (d->has_pen) { - const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height())); - XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y()); - } - continue; - } - - r = r.intersected(clip); - if (r.isEmpty()) - continue; - if (d->has_texture || d->has_pattern) { - XRenderComposite(d->dpy, d->composition_mode, d->current_brush, 0, pict, - qRound(r.x() - d->bg_origin.x()), qRound(r.y() - d->bg_origin.y()), - 0, 0, r.x(), r.y(), r.width(), r.height()); - } else { - XRenderFillRectangle(d->dpy, d->composition_mode, pict, &xc, r.x(), r.y(), r.width(), r.height()); - } - if (d->has_pen) - XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height()); - } - } else -#endif // QT_CONFIG(xrender) - { - if (d->has_brush && d->has_pen) { - for (int i = 0; i < rectCount; ++i) { - QRect r(rects[i]); - if (d->txop == QTransform::TxTranslate) - r.translate(offset); - - if (r.width() == 0 || r.height() == 0) { - const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height())); - XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y()); - continue; - } - - r = r.intersected(clip); - if (r.isEmpty()) - continue; - d->setupAdaptedOrigin(r.topLeft()); - XFillRectangle(d->dpy, d->hd, d->gc_brush, r.x(), r.y(), r.width(), r.height()); - XDrawRectangle(d->dpy, d->hd, d->gc, r.x(), r.y(), r.width(), r.height()); - } - d->resetAdaptedOrigin(); - } else { - QVarLengthArray<XRectangle> xrects(rectCount); - int numClipped = rectCount; - for (int i = 0; i < rectCount; ++i) { - QRect r(rects[i]); - if (d->txop == QTransform::TxTranslate) - r.translate(offset); - - if (r.width() == 0 || r.height() == 0) { - --numClipped; - if (d->has_pen) { - const QLine l = clipStraightLine(clip, QLine(r.left(), r.top(), r.left() + r.width(), r.top() + r.height())); - XDrawLine(d->dpy, d->hd, d->gc, l.p1().x(), l.p1().y(), l.p2().x(), l.p2().y()); - } - continue; - } - - r = r.intersected(clip); - if (r.isEmpty()) { - --numClipped; - continue; - } - xrects[i].x = short(r.x()); - xrects[i].y = short(r.y()); - xrects[i].width = ushort(r.width()); - xrects[i].height = ushort(r.height()); - } - if (numClipped) { - d->setupAdaptedOrigin(rects[0].topLeft()); - if (d->has_brush) - XFillRectangles(d->dpy, d->hd, d->gc_brush, xrects.data(), numClipped); - else if (d->has_pen) - XDrawRectangles(d->dpy, d->hd, d->gc, xrects.data(), numClipped); - d->resetAdaptedOrigin(); - } - } - } -} - -static inline void setCapStyle(int cap_style, GC gc) -{ - ulong mask = GCCapStyle; - XGCValues vals; - vals.cap_style = cap_style; - XChangeGC(QXcbX11Info::display(), gc, mask, &vals); -} - -void QX11PaintEngine::drawPoints(const QPoint *points, int pointCount) -{ - Q_ASSERT(points); - Q_ASSERT(pointCount); - Q_D(QX11PaintEngine); - - if (!d->has_pen) - return; - - // use the same test here as in drawPath to ensure that we don't use the path fallback - // and end up in XDrawLines for pens with width <= 1 - if (d->cpen.widthF() > 1.0f - || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing))) - || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate)) - { - Qt::PenCapStyle capStyle = d->cpen.capStyle(); - if (capStyle == Qt::FlatCap) { - setCapStyle(CapProjecting, d->gc); - d->cpen.setCapStyle(Qt::SquareCap); - } - const QPoint *end = points + pointCount; - while (points < end) { - QPainterPath path; - path.moveTo(*points); - path.lineTo(points->x()+.005, points->y()); - drawPath(path); - ++points; - } - - if (capStyle == Qt::FlatCap) { - setCapStyle(CapButt, d->gc); - d->cpen.setCapStyle(capStyle); - } - return; - } - - static const int BUF_SIZE = 1024; - XPoint xPoints[BUF_SIZE]; - int i = 0, j = 0; - while (i < pointCount) { - while (i < pointCount && j < BUF_SIZE) { - const QPoint &xformed = d->matrix.map(points[i]); - int x = xformed.x(); - int y = xformed.y(); - if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) { - xPoints[j].x = x; - xPoints[j].y = y; - ++j; - } - ++i; - } - if (j) - XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin); - - j = 0; - } -} - -void QX11PaintEngine::drawPoints(const QPointF *points, int pointCount) -{ - Q_ASSERT(points); - Q_ASSERT(pointCount); - Q_D(QX11PaintEngine); - - if (!d->has_pen) - return; - - // use the same test here as in drawPath to ensure that we don't use the path fallback - // and end up in XDrawLines for pens with width <= 1 - if (d->cpen.widthF() > 1.0f - || (X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing))) - || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate)) - { - Qt::PenCapStyle capStyle = d->cpen.capStyle(); - if (capStyle == Qt::FlatCap) { - setCapStyle(CapProjecting, d->gc); - d->cpen.setCapStyle(Qt::SquareCap); - } - - const QPointF *end = points + pointCount; - while (points < end) { - QPainterPath path; - path.moveTo(*points); - path.lineTo(points->x() + 0.005, points->y()); - drawPath(path); - ++points; - } - if (capStyle == Qt::FlatCap) { - setCapStyle(CapButt, d->gc); - d->cpen.setCapStyle(capStyle); - } - return; - } - - static const int BUF_SIZE = 1024; - XPoint xPoints[BUF_SIZE]; - int i = 0, j = 0; - while (i < pointCount) { - while (i < pointCount && j < BUF_SIZE) { - const QPointF &xformed = d->matrix.map(points[i]); - int x = qFloor(xformed.x()); - int y = qFloor(xformed.y()); - - if (x >= SHRT_MIN && y >= SHRT_MIN && x < SHRT_MAX && y < SHRT_MAX) { - xPoints[j].x = x; - xPoints[j].y = y; - ++j; - } - ++i; - } - if (j) - XDrawPoints(d->dpy, d->hd, d->gc, xPoints, j, CoordModeOrigin); - - j = 0; - } -} - -QPainter::RenderHints QX11PaintEngine::supportedRenderHints() const -{ -#if QT_CONFIG(xrender) - if (X11->use_xrender) - return QPainter::Antialiasing; -#endif - return QFlag(0); -} - -void QX11PaintEngine::updateState(const QPaintEngineState &state) -{ - Q_D(QX11PaintEngine); - QPaintEngine::DirtyFlags flags = state.state(); - - - if (flags & DirtyOpacity) { - d->opacity = state.opacity(); - // Force update pen/brush as to get proper alpha colors propagated - flags |= DirtyPen; - flags |= DirtyBrush; - } - - if (flags & DirtyTransform) updateMatrix(state.transform()); - if (flags & DirtyPen) updatePen(state.pen()); - if (flags & (DirtyBrush | DirtyBrushOrigin)) updateBrush(state.brush(), state.brushOrigin()); - if (flags & DirtyFont) updateFont(state.font()); - - if (state.state() & DirtyClipEnabled) { - if (state.isClipEnabled()) { - QPolygonF clip_poly_dev(d->matrix.map(painter()->clipPath().toFillPolygon())); - QPolygonF clipped_poly_dev; - d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev); - updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), Qt::ReplaceClip); - } else { - updateClipRegion_dev(QRegion(), Qt::NoClip); - } - } - - if (flags & DirtyClipPath) { - QPolygonF clip_poly_dev(d->matrix.map(state.clipPath().toFillPolygon())); - QPolygonF clipped_poly_dev; - d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev); - updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon(), state.clipPath().fillRule()), - state.clipOperation()); - } else if (flags & DirtyClipRegion) { - extern QPainterPath qt_regionToPath(const QRegion ®ion); - QPainterPath clip_path = qt_regionToPath(state.clipRegion()); - QPolygonF clip_poly_dev(d->matrix.map(clip_path.toFillPolygon())); - QPolygonF clipped_poly_dev; - d->clipPolygon_dev(clip_poly_dev, &clipped_poly_dev); - updateClipRegion_dev(QRegion(clipped_poly_dev.toPolygon()), state.clipOperation()); - } - if (flags & DirtyHints) updateRenderHints(state.renderHints()); - if (flags & DirtyCompositionMode) { - int function = GXcopy; - if (state.compositionMode() >= QPainter::RasterOp_SourceOrDestination) { - switch (state.compositionMode()) { - case QPainter::RasterOp_SourceOrDestination: - function = GXor; - break; - case QPainter::RasterOp_SourceAndDestination: - function = GXand; - break; - case QPainter::RasterOp_SourceXorDestination: - function = GXxor; - break; - case QPainter::RasterOp_NotSourceAndNotDestination: - function = GXnor; - break; - case QPainter::RasterOp_NotSourceOrNotDestination: - function = GXnand; - break; - case QPainter::RasterOp_NotSourceXorDestination: - function = GXequiv; - break; - case QPainter::RasterOp_NotSource: - function = GXcopyInverted; - break; - case QPainter::RasterOp_SourceAndNotDestination: - function = GXandReverse; - break; - case QPainter::RasterOp_NotSourceAndDestination: - function = GXandInverted; - break; - default: - function = GXcopy; - } - } -#if QT_CONFIG(xrender) - else { - d->composition_mode = - qpainterOpToXrender(state.compositionMode()); - } -#endif - XSetFunction(X11->display, d->gc, function); - XSetFunction(X11->display, d->gc_brush, function); - } - d->decidePathFallback(); - d->decideCoordAdjust(); -} - -void QX11PaintEngine::updateRenderHints(QPainter::RenderHints hints) -{ - Q_D(QX11PaintEngine); - d->render_hints = hints; - -#if QT_CONFIG(xrender) - if (X11->use_xrender && d->picture) { - XRenderPictureAttributes attrs; - attrs.poly_edge = (hints & QPainter::Antialiasing) ? PolyEdgeSmooth : PolyEdgeSharp; - XRenderChangePicture(d->dpy, d->picture, CPPolyEdge, &attrs); - } -#endif -} - -void QX11PaintEngine::updatePen(const QPen &pen) -{ - Q_D(QX11PaintEngine); - d->cpen = pen; - int cp = CapButt; - int jn = JoinMiter; - int ps = pen.style(); - - if (d->opacity < 1.0) { - QColor c = d->cpen.color(); - c.setAlpha(qRound(c.alpha()*d->opacity)); - d->cpen.setColor(c); - } - - d->has_pen = (ps != Qt::NoPen); - d->has_alpha_pen = (pen.color().alpha() != 255); - - switch (pen.capStyle()) { - case Qt::SquareCap: - cp = CapProjecting; - break; - case Qt::RoundCap: - cp = CapRound; - break; - case Qt::FlatCap: - default: - cp = CapButt; - break; - } - switch (pen.joinStyle()) { - case Qt::BevelJoin: - jn = JoinBevel; - break; - case Qt::RoundJoin: - jn = JoinRound; - break; - case Qt::MiterJoin: - default: - jn = JoinMiter; - break; - } - - d->adapted_pen_origin = false; - - char dashes[10]; // custom pen dashes - int dash_len = 0; // length of dash list - int xStyle = LineSolid; - - /* - We are emulating Windows here. Windows treats cpen.width() == 1 - (or 0) as a very special case. The fudge variable unifies this - case with the general case. - */ - qreal pen_width = pen.widthF(); - int scale = qRound(pen_width < 1 ? 1 : pen_width); - int space = (pen_width < 1 && pen_width > 0 ? 1 : (2 * scale)); - int dot = 1 * scale; - int dash = 4 * scale; - - d->has_custom_pen = false; - - switch (ps) { - case Qt::NoPen: - case Qt::SolidLine: - xStyle = LineSolid; - break; - case Qt::DashLine: - dashes[0] = dash; - dashes[1] = space; - dash_len = 2; - xStyle = LineOnOffDash; - break; - case Qt::DotLine: - dashes[0] = dot; - dashes[1] = space; - dash_len = 2; - xStyle = LineOnOffDash; - break; - case Qt::DashDotLine: - dashes[0] = dash; - dashes[1] = space; - dashes[2] = dot; - dashes[3] = space; - dash_len = 4; - xStyle = LineOnOffDash; - break; - case Qt::DashDotDotLine: - dashes[0] = dash; - dashes[1] = space; - dashes[2] = dot; - dashes[3] = space; - dashes[4] = dot; - dashes[5] = space; - dash_len = 6; - xStyle = LineOnOffDash; - break; - case Qt::CustomDashLine: - d->has_custom_pen = true; - break; - } - - ulong mask = GCForeground | GCBackground | GCGraphicsExposures | GCLineWidth - | GCCapStyle | GCJoinStyle | GCLineStyle; - XGCValues vals; - vals.graphics_exposures = false; - if (d->pdev_depth == 1) { - vals.foreground = qGray(pen.color().rgb()) > 127 ? 0 : 1; - vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1; - } else if (d->pdev->devType() == QInternal::Pixmap && d->pdev_depth == 32 - && X11->use_xrender) { - vals.foreground = pen.color().rgba(); - vals.background = QColor(Qt::transparent).rgba(); - } else { - QXcbColormap cmap = QXcbColormap::instance(d->scrn); - vals.foreground = cmap.pixel(pen.color()); - vals.background = cmap.pixel(QColor(Qt::transparent)); - } - - - vals.line_width = qRound(pen.widthF()); - vals.cap_style = cp; - vals.join_style = jn; - vals.line_style = xStyle; - - XChangeGC(d->dpy, d->gc, mask, &vals); - - if (dash_len) { // make dash list - XSetDashes(d->dpy, d->gc, 0, dashes, dash_len); - } - - if (!d->has_clipping) { // if clipping is set the paintevent clip region is merged with the clip region - QRegion sysClip = d->use_sysclip ? systemClip() : QRegion(); - if (!sysClip.isEmpty()) - x11SetClipRegion(d->dpy, d->gc, 0, d->picture, sysClip); - else - x11ClearClipRegion(d->dpy, d->gc, 0, d->picture); - } -} - -void QX11PaintEngine::updateBrush(const QBrush &brush, const QPointF &origin) -{ - Q_D(QX11PaintEngine); - d->cbrush = brush; - d->bg_origin = origin; - d->adapted_brush_origin = false; -#if QT_CONFIG(xrender) - d->current_brush = 0; -#endif - if (d->opacity < 1.0) { - QColor c = d->cbrush.color(); - c.setAlpha(qRound(c.alpha()*d->opacity)); - d->cbrush.setColor(c); - } - - int s = FillSolid; - int bs = d->cbrush.style(); - d->has_brush = (bs != Qt::NoBrush); - d->has_pattern = bs >= Qt::Dense1Pattern && bs <= Qt::DiagCrossPattern; - d->has_texture = bs == Qt::TexturePattern; - d->has_alpha_brush = brush.color().alpha() != 255; - d->has_alpha_texture = d->has_texture && d->cbrush.texture().hasAlphaChannel(); - - ulong mask = GCForeground | GCBackground | GCGraphicsExposures - | GCLineStyle | GCCapStyle | GCJoinStyle | GCFillStyle; - XGCValues vals; - vals.graphics_exposures = false; - if (d->pdev_depth == 1) { - vals.foreground = qGray(d->cbrush.color().rgb()) > 127 ? 0 : 1; - vals.background = qGray(QColor(Qt::transparent).rgb()) > 127 ? 0 : 1; - } else if (X11->use_xrender && d->pdev->devType() == QInternal::Pixmap - && d->pdev_depth == 32) { - vals.foreground = d->cbrush.color().rgba(); - vals.background = QColor(Qt::transparent).rgba(); - } else { - QXcbColormap cmap = QXcbColormap::instance(d->scrn); - vals.foreground = cmap.pixel(d->cbrush.color()); - vals.background = cmap.pixel(QColor(Qt::transparent)); - - if (!X11->use_xrender && d->has_brush && !d->has_pattern && !brush.isOpaque()) { - QPixmap pattern = qt_patternForAlpha(brush.color().alpha(), d->scrn); - mask |= GCStipple; - vals.stipple = qt_x11PixmapHandle(pattern); - s = FillStippled; - d->adapted_brush_origin = true; - } - } - vals.cap_style = CapButt; - vals.join_style = JoinMiter; - vals.line_style = LineSolid; - - if (d->has_pattern || d->has_texture) { - if (bs == Qt::TexturePattern) { - d->brush_pm = qt_toX11Pixmap(d->cbrush.texture()); -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - XRenderPictureAttributes attrs; - attrs.repeat = true; - XRenderChangePicture(d->dpy, qt_x11PictureHandle(d->brush_pm), CPRepeat, &attrs); - QX11PlatformPixmap *data = static_cast<QX11PlatformPixmap*>(d->brush_pm.handle()); - if (data->mask_picture) - XRenderChangePicture(d->dpy, data->mask_picture, CPRepeat, &attrs); - } -#endif - } else { - d->brush_pm = qt_toX11Pixmap(qt_pixmapForBrush(bs, true)); - } - qt_x11SetScreen(d->brush_pm, d->scrn); - if (d->brush_pm.depth() == 1) { - mask |= GCStipple; - vals.stipple = qt_x11PixmapHandle(d->brush_pm); - s = FillStippled; -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - d->bitmap_texture = QPixmap(d->brush_pm.size()); - d->bitmap_texture.fill(Qt::transparent); - d->bitmap_texture = qt_toX11Pixmap(d->bitmap_texture); - qt_x11SetScreen(d->bitmap_texture, d->scrn); - - ::Picture src = X11->getSolidFill(d->scrn, d->cbrush.color()); - XRenderComposite(d->dpy, PictOpSrc, src, qt_x11PictureHandle(d->brush_pm), - qt_x11PictureHandle(d->bitmap_texture), - 0, 0, d->brush_pm.width(), d->brush_pm.height(), - 0, 0, d->brush_pm.width(), d->brush_pm.height()); - - XRenderPictureAttributes attrs; - attrs.repeat = true; - XRenderChangePicture(d->dpy, qt_x11PictureHandle(d->bitmap_texture), CPRepeat, &attrs); - - d->current_brush = qt_x11PictureHandle(d->bitmap_texture); - } -#endif - } else { - mask |= GCTile; -#if QT_CONFIG(xrender) - if (d->pdev_depth == 32 && d->brush_pm.depth() != 32) { - d->brush_pm.detach(); - QX11PlatformPixmap *brushData = static_cast<QX11PlatformPixmap*>(d->brush_pm.handle()); - brushData->convertToARGB32(); - } -#endif - vals.tile = (d->brush_pm.depth() == d->pdev_depth - ? qt_x11PixmapHandle(d->brush_pm) - : static_cast<QX11PlatformPixmap*>(d->brush_pm.handle())->x11ConvertToDefaultDepth()); - s = FillTiled; -#if QT_CONFIG(xrender) - d->current_brush = qt_x11PictureHandle(d->cbrush.texture()); -#endif - } - - mask |= GCTileStipXOrigin | GCTileStipYOrigin; - vals.ts_x_origin = qRound(origin.x()); - vals.ts_y_origin = qRound(origin.y()); - } -#if QT_CONFIG(xrender) - else if (d->has_alpha_brush) { - d->current_brush = X11->getSolidFill(d->scrn, d->cbrush.color()); - } -#endif - - vals.fill_style = s; - XChangeGC(d->dpy, d->gc_brush, mask, &vals); - if (!d->has_clipping) { - QRegion sysClip = d->use_sysclip ? systemClip() : QRegion(); - if (!sysClip.isEmpty()) - x11SetClipRegion(d->dpy, d->gc_brush, 0, d->picture, sysClip); - else - x11ClearClipRegion(d->dpy, d->gc_brush, 0, d->picture); - } -} - -void QX11PaintEngine::drawEllipse(const QRectF &rect) -{ - QRect aligned = rect.toAlignedRect(); - if (aligned == rect) - drawEllipse(aligned); - else - QPaintEngine::drawEllipse(rect); -} - -void QX11PaintEngine::drawEllipse(const QRect &rect) -{ - if (rect.isEmpty()) { - drawRects(&rect, 1); - return; - } - - Q_D(QX11PaintEngine); - QRect devclip(SHRT_MIN, SHRT_MIN, SHRT_MAX*2 - 1, SHRT_MAX*2 - 1); - QRect r(rect); - if (d->txop < QTransform::TxRotate) { - r = d->matrix.mapRect(rect); - } else if (d->txop == QTransform::TxRotate && rect.width() == rect.height()) { - QPainterPath path; - path.addEllipse(rect); - r = d->matrix.map(path).boundingRect().toRect(); - } - - if (d->has_alpha_brush || d->has_alpha_pen || d->has_custom_pen || (d->render_hints & QPainter::Antialiasing) - || d->has_alpha_texture || devclip.intersected(r) != r - || (d->has_complex_xform - && !(d->has_non_scaling_xform && rect.width() == rect.height()))) - { - QPainterPath path; - path.addEllipse(rect); - drawPath(path); - return; - } - - int x = r.x(); - int y = r.y(); - int w = r.width(); - int h = r.height(); - if (w < 1 || h < 1) - return; - if (w == 1 && h == 1) { - XDrawPoint(d->dpy, d->hd, d->has_pen ? d->gc : d->gc_brush, x, y); - return; - } - d->setupAdaptedOrigin(rect.topLeft()); - if (d->has_brush) { // draw filled ellipse - XFillArc(d->dpy, d->hd, d->gc_brush, x, y, w, h, 0, 360*64); - if (!d->has_pen) // make smoother outline - XDrawArc(d->dpy, d->hd, d->gc_brush, x, y, w-1, h-1, 0, 360*64); - } - if (d->has_pen) // draw outline - XDrawArc(d->dpy, d->hd, d->gc, x, y, w, h, 0, 360*64); - d->resetAdaptedOrigin(); -} - - - -void QX11PaintEnginePrivate::fillPolygon_translated(const QPointF *polygonPoints, int pointCount, - QX11PaintEnginePrivate::GCMode gcMode, - QPaintEngine::PolygonDrawMode mode) -{ - - QVarLengthArray<QPointF> translated_points(pointCount); - QPointF offset(matrix.dx(), matrix.dy()); - - qreal offs = adjust_coords ? aliasedCoordinateDelta : 0.0; - if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing)) - offset += QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta); - - for (int i = 0; i < pointCount; ++i) { - translated_points[i] = polygonPoints[i] + offset; - - translated_points[i].rx() = qRound(translated_points[i].x()) + offs; - translated_points[i].ry() = qRound(translated_points[i].y()) + offs; - } - - fillPolygon_dev(translated_points.data(), pointCount, gcMode, mode); -} - -#if QT_CONFIG(xrender) -static void qt_XRenderCompositeTrapezoids(Display *dpy, - int op, - Picture src, - Picture dst, - _Xconst XRenderPictFormat *maskFormat, - int xSrc, - int ySrc, - const XTrapezoid *traps, int size) -{ - const int MAX_TRAPS = 50000; - while (size) { - int to_draw = size; - if (to_draw > MAX_TRAPS) - to_draw = MAX_TRAPS; - XRenderCompositeTrapezoids(dpy, op, src, dst, - maskFormat, - xSrc, ySrc, - traps, to_draw); - size -= to_draw; - traps += to_draw; - } -} -#endif - -void QX11PaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int pointCount, - QX11PaintEnginePrivate::GCMode gcMode, - QPaintEngine::PolygonDrawMode mode) -{ - Q_Q(QX11PaintEngine); - - int clippedCount = 0; - qt_float_point *clippedPoints = 0; - -#if QT_CONFIG(xrender) - //can change if we switch to pen if gcMode != BrushGC - bool has_fill_texture = has_texture; - bool has_fill_pattern = has_pattern; - ::Picture src; -#endif - QBrush fill; - GC fill_gc; - if (gcMode == BrushGC) { - fill = cbrush; - fill_gc = gc_brush; -#if QT_CONFIG(xrender) - if (current_brush) - src = current_brush; - else - src = X11->getSolidFill(scrn, fill.color()); -#endif - } else { - fill = QBrush(cpen.brush()); - fill_gc = gc; -#if QT_CONFIG(xrender) - //we use the pens brush - has_fill_texture = (fill.style() == Qt::TexturePattern); - has_fill_pattern = (fill.style() >= Qt::Dense1Pattern && fill.style() <= Qt::DiagCrossPattern); - if (has_fill_texture) - src = qt_x11PictureHandle(fill.texture()); - else if (has_fill_pattern) - src = getPatternFill(scrn, fill); - else - src = X11->getSolidFill(scrn, fill.color()); -#endif - } - - polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount, - &clippedPoints, &clippedCount); - -#if QT_CONFIG(xrender) - bool solid_fill = fill.color().alpha() == 255; - if (has_fill_texture && fill.texture().depth() == 1 && solid_fill) { - has_fill_texture = false; - has_fill_pattern = true; - } - - bool antialias = render_hints & QPainter::Antialiasing; - - if (X11->use_xrender - && picture - && !has_fill_pattern - && (clippedCount > 0) - && (fill.style() != Qt::NoBrush) - && ((has_fill_texture && fill.texture().hasAlpha()) || antialias || !solid_fill || has_alpha_pen != has_alpha_brush)) - { - tessellator->tessellate((QPointF *)clippedPoints, clippedCount, - mode == QPaintEngine::WindingMode); - if (tessellator->size > 0) { - XRenderPictureAttributes attrs; - attrs.poly_edge = antialias ? PolyEdgeSmooth : PolyEdgeSharp; - XRenderChangePicture(dpy, picture, CPPolyEdge, &attrs); - int x_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.x) - bg_origin.x()); - int y_offset = int(XFixedToDouble(tessellator->traps[0].left.p1.y) - bg_origin.y()); - qt_XRenderCompositeTrapezoids(dpy, composition_mode, src, picture, - antialias - ? XRenderFindStandardFormat(dpy, PictStandardA8) - : XRenderFindStandardFormat(dpy, PictStandardA1), - x_offset, y_offset, - tessellator->traps, tessellator->size); - tessellator->done(); - } - } else -#endif - if (fill.style() != Qt::NoBrush) { - if (clippedCount > 200000) { - QPolygon poly; - for (int i = 0; i < clippedCount; ++i) - poly << QPoint(qFloor(clippedPoints[i].x), qFloor(clippedPoints[i].y)); - - const QRect bounds = poly.boundingRect(); - const QRect aligned = bounds - & QRect(QPoint(), QSize(pdev->width(), pdev->height())); - - QImage img(aligned.size(), QImage::Format_ARGB32_Premultiplied); - img.fill(0); - - QPainter painter(&img); - painter.translate(-aligned.x(), -aligned.y()); - painter.setPen(Qt::NoPen); - painter.setBrush(fill); - if (gcMode == BrushGC) - painter.setBrushOrigin(q->painter()->brushOriginF()); - painter.drawPolygon(poly); - painter.end(); - - q->drawImage(aligned, img, img.rect(), Qt::AutoColor); - } else if (clippedCount > 0) { - QVarLengthArray<XPoint> xpoints(clippedCount); - for (int i = 0; i < clippedCount; ++i) { - xpoints[i].x = qFloor(clippedPoints[i].x); - xpoints[i].y = qFloor(clippedPoints[i].y); - } - if (mode == QPaintEngine::WindingMode) - XSetFillRule(dpy, fill_gc, WindingRule); - setupAdaptedOrigin(QPoint(xpoints[0].x, xpoints[0].y)); - XFillPolygon(dpy, hd, fill_gc, - xpoints.data(), clippedCount, - mode == QPaintEngine::ConvexMode ? Convex : Complex, CoordModeOrigin); - resetAdaptedOrigin(); - if (mode == QPaintEngine::WindingMode) - XSetFillRule(dpy, fill_gc, EvenOddRule); - } - } -} - -void QX11PaintEnginePrivate::strokePolygon_translated(const QPointF *polygonPoints, int pointCount, bool close) -{ - QVarLengthArray<QPointF> translated_points(pointCount); - QPointF offset(matrix.dx(), matrix.dy()); - for (int i = 0; i < pointCount; ++i) - translated_points[i] = polygonPoints[i] + offset; - strokePolygon_dev(translated_points.data(), pointCount, close); -} - -void QX11PaintEnginePrivate::strokePolygon_dev(const QPointF *polygonPoints, int pointCount, bool close) -{ - int clippedCount = 0; - qt_float_point *clippedPoints = 0; - polygonClipper.clipPolygon((qt_float_point *) polygonPoints, pointCount, - &clippedPoints, &clippedCount, close); - - if (clippedCount > 0) { - QVarLengthArray<XPoint> xpoints(clippedCount); - for (int i = 0; i < clippedCount; ++i) { - xpoints[i].x = qRound(clippedPoints[i].x + aliasedCoordinateDelta); - xpoints[i].y = qRound(clippedPoints[i].y + aliasedCoordinateDelta); - } - uint numberPoints = qMin(clippedCount, xlibMaxLinePoints); - XPoint *pts = xpoints.data(); - XDrawLines(dpy, hd, gc, pts, numberPoints, CoordModeOrigin); - pts += numberPoints; - clippedCount -= numberPoints; - numberPoints = qMin(clippedCount, xlibMaxLinePoints-1); - while (clippedCount) { - XDrawLines(dpy, hd, gc, pts-1, numberPoints+1, CoordModeOrigin); - pts += numberPoints; - clippedCount -= numberPoints; - numberPoints = qMin(clippedCount, xlibMaxLinePoints-1); - } - } -} - -void QX11PaintEngine::drawPolygon(const QPointF *polygonPoints, int pointCount, PolygonDrawMode mode) -{ - Q_D(QX11PaintEngine); - - if (d->use_path_fallback) { - QPainterPath path(polygonPoints[0]); - for (int i = 1; i < pointCount; ++i) - path.lineTo(polygonPoints[i]); - if (mode == PolylineMode) { - QBrush oldBrush = d->cbrush; - d->cbrush = QBrush(Qt::NoBrush); - path.setFillRule(Qt::WindingFill); - drawPath(path); - d->cbrush = oldBrush; - } else { - path.setFillRule(mode == OddEvenMode ? Qt::OddEvenFill : Qt::WindingFill); - path.closeSubpath(); - drawPath(path); - } - return; - } - if (mode != PolylineMode && d->has_brush) - d->fillPolygon_translated(polygonPoints, pointCount, QX11PaintEnginePrivate::BrushGC, mode); - - if (d->has_pen) - d->strokePolygon_translated(polygonPoints, pointCount, mode != PolylineMode); -} - - -void QX11PaintEnginePrivate::fillPath(const QPainterPath &path, QX11PaintEnginePrivate::GCMode gc_mode, bool transform) -{ - qreal offs = adjust_coords ? aliasedCoordinateDelta : 0.0; - - QPainterPath clippedPath; - QPainterPath clipPath; - clipPath.addRect(polygonClipper.boundingRect()); - - if (transform) - clippedPath = (path*matrix).intersected(clipPath); - else - clippedPath = path.intersected(clipPath); - - QList<QPolygonF> polys = clippedPath.toFillPolygons(); - for (int i = 0; i < polys.size(); ++i) { - QVarLengthArray<QPointF> translated_points(polys.at(i).size()); - - for (int j = 0; j < polys.at(i).size(); ++j) { - translated_points[j] = polys.at(i).at(j); - if (!X11->use_xrender || !(render_hints & QPainter::Antialiasing)) { - translated_points[j].rx() = qRound(translated_points[j].rx() + aliasedCoordinateDelta) + offs; - translated_points[j].ry() = qRound(translated_points[j].ry() + aliasedCoordinateDelta) + offs; - } - } - - fillPolygon_dev(translated_points.data(), polys.at(i).size(), gc_mode, - path.fillRule() == Qt::OddEvenFill ? QPaintEngine::OddEvenMode : QPaintEngine::WindingMode); - } -} - -void QX11PaintEngine::drawPath(const QPainterPath &path) -{ - Q_D(QX11PaintEngine); - if (path.isEmpty()) - return; - - if (d->has_brush) - d->fillPath(path, QX11PaintEnginePrivate::BrushGC, true); - if (d->has_pen - && ((X11->use_xrender && (d->has_alpha_pen || (d->render_hints & QPainter::Antialiasing))) - || (!d->isCosmeticPen() && d->txop > QTransform::TxTranslate - && !d->has_non_scaling_xform) - || (d->cpen.style() == Qt::CustomDashLine))) { - QPainterPathStroker stroker; - if (d->cpen.style() == Qt::CustomDashLine) { - stroker.setDashPattern(d->cpen.dashPattern()); - stroker.setDashOffset(d->cpen.dashOffset()); - } else { - stroker.setDashPattern(d->cpen.style()); - } - stroker.setCapStyle(d->cpen.capStyle()); - stroker.setJoinStyle(d->cpen.joinStyle()); - QPainterPath stroke; - qreal width = d->cpen.widthF(); - QPolygonF poly; - QRectF deviceRect(0, 0, d->pdev->width(), d->pdev->height()); - // necessary to get aliased alphablended primitives to be drawn correctly - if (d->isCosmeticPen() || d->has_scaling_xform) { - if (d->isCosmeticPen()) - stroker.setWidth(width == 0 ? 1 : width); - else - stroker.setWidth(width * d->xform_scale); - stroker.d_ptr->stroker.setClipRect(deviceRect); - stroke = stroker.createStroke(path * d->matrix); - if (stroke.isEmpty()) - return; - stroke.setFillRule(Qt::WindingFill); - d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, false); - } else { - stroker.setWidth(width); - stroker.d_ptr->stroker.setClipRect(d->matrix.inverted().mapRect(deviceRect)); - stroke = stroker.createStroke(path); - if (stroke.isEmpty()) - return; - stroke.setFillRule(Qt::WindingFill); - d->fillPath(stroke, QX11PaintEnginePrivate::PenGC, true); - } - } else if (d->has_pen) { - // if we have a cosmetic pen - use XDrawLine() for speed - QList<QPolygonF> polys = path.toSubpathPolygons(d->matrix); - for (int i = 0; i < polys.size(); ++i) - d->strokePolygon_dev(polys.at(i).data(), polys.at(i).size(), false); - } -} - -Q_GUI_EXPORT void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, - Drawable hd, GC gc, Display *dpy, Visual *visual, int depth) -{ - Q_ASSERT(image.format() == QImage::Format_RGB32); - Q_ASSERT(image.depth() == 32); - - XImage *xi; - // Note: this code assumes either RGB or BGR, 8 bpc server layouts - const uint red_mask = (uint) visual->red_mask; - bool bgr_layout = (red_mask == 0xff); - - const int w = rect.width(); - const int h = rect.height(); - - QImage im; - int image_byte_order = ImageByteOrder(QXcbX11Info::display()); - if ((QSysInfo::ByteOrder == QSysInfo::BigEndian && ((image_byte_order == LSBFirst) || bgr_layout)) - || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian) - || (image_byte_order == LSBFirst && bgr_layout)) - { - im = image.copy(rect); - const qsizetype iw = im.bytesPerLine() / 4; - uint *data = (uint *)im.bits(); - for (int i=0; i < h; i++) { - uint *p = data; - uint *end = p + w; - if (bgr_layout && image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian) { - while (p < end) { - *p = ((*p << 8) & 0xffffff00) | ((*p >> 24) & 0x000000ff); - p++; - } - } else if ((image_byte_order == LSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) - || (image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { - while (p < end) { - *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) - | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); - p++; - } - } else if ((image_byte_order == MSBFirst && QSysInfo::ByteOrder == QSysInfo::BigEndian) - || (image_byte_order == LSBFirst && bgr_layout)) - { - while (p < end) { - *p = ((*p << 16) & 0x00ff0000) | ((*p >> 16) & 0x000000ff) - | ((*p ) & 0xff00ff00); - p++; - } - } - data += iw; - } - xi = XCreateImage(dpy, visual, depth, ZPixmap, - 0, (char *) im.bits(), w, h, 32, im.bytesPerLine()); - } else { - xi = XCreateImage(dpy, visual, depth, ZPixmap, - 0, (char *) image.scanLine(rect.y())+rect.x()*sizeof(uint), w, h, 32, image.bytesPerLine()); - } - XPutImage(dpy, hd, gc, xi, 0, 0, pos.x(), pos.y(), w, h); - xi->data = 0; // QImage owns these bits - XDestroyImage(xi); -} - -void QX11PaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags) -{ - Q_D(QX11PaintEngine); - - if (image.format() == QImage::Format_RGB32 - && d->pdev_depth >= 24 && image.depth() == 32 - && r.size() == sr.size()) - { - int sx = qRound(sr.x()); - int sy = qRound(sr.y()); - int x = qRound(r.x()); - int y = qRound(r.y()); - int w = qRound(r.width()); - int h = qRound(r.height()); - - qt_x11_drawImage(QRect(sx, sy, w, h), QPoint(x, y), image, d->hd, d->gc, d->dpy, - (Visual *)d->xinfo->visual(), d->pdev_depth); - } else { - QPaintEngine::drawImage(r, image, sr, flags); - } -} - -void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRectF &_sr) -{ - Q_D(QX11PaintEngine); - QRectF sr = _sr; - int x = qRound(r.x()); - int y = qRound(r.y()); - int sx = qRound(sr.x()); - int sy = qRound(sr.y()); - int sw = qRound(sr.width()); - int sh = qRound(sr.height()); - - QPixmap pixmap = qt_toX11Pixmap(px); - if (pixmap.isNull()) - return; - - if ((d->xinfo && d->xinfo->screen() != qt_x11Info(pixmap).screen()) - || (qt_x11Info(pixmap).screen() != DefaultScreen(QXcbX11Info::display()))) { - qt_x11SetScreen(pixmap, d->xinfo ? d->xinfo->screen() : DefaultScreen(X11->display)); - } - - qt_x11SetDefaultScreen(qt_x11Info(pixmap).screen()); - -#if QT_CONFIG(xrender) - ::Picture src_pict = qt_x11PictureHandle(pixmap); - if (src_pict && d->picture) { - const int pDepth = pixmap.depth(); - if (pDepth == 1 && (d->has_alpha_pen)) { - qt_render_bitmap(d->dpy, d->scrn, src_pict, d->picture, - sx, sy, x, y, sw, sh, d->cpen); - return; - } else if (pDepth != 1 && (pDepth == 32 || pDepth != d->pdev_depth)) { - XRenderComposite(d->dpy, d->composition_mode, - src_pict, 0, d->picture, sx, sy, 0, 0, x, y, sw, sh); - return; - } - } -#endif - - bool mono_src = pixmap.depth() == 1; - bool mono_dst = d->pdev_depth == 1; - bool restore_clip = false; - - if (static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask) { // pixmap has a mask - QBitmap comb(sw, sh); - GC cgc = XCreateGC(d->dpy, qt_x11PixmapHandle(comb), 0, 0); - XSetForeground(d->dpy, cgc, 0); - XFillRectangle(d->dpy, qt_x11PixmapHandle(comb), cgc, 0, 0, sw, sh); - XSetBackground(d->dpy, cgc, 0); - XSetForeground(d->dpy, cgc, 1); - if (!d->crgn.isEmpty()) { - QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn); - XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted); - } else if (d->has_clipping) { - XSetClipRectangles(d->dpy, cgc, 0, 0, 0, 0, Unsorted); - } - XSetFillStyle(d->dpy, cgc, FillOpaqueStippled); - XSetTSOrigin(d->dpy, cgc, -sx, -sy); - XSetStipple(d->dpy, cgc, - static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask); - XFillRectangle(d->dpy, qt_x11PixmapHandle(comb), cgc, 0, 0, sw, sh); - XFreeGC(d->dpy, cgc); - - XSetClipOrigin(d->dpy, d->gc, x, y); - XSetClipMask(d->dpy, d->gc, qt_x11PixmapHandle(comb)); - restore_clip = true; - } - - if (mono_src) { - if (!d->crgn.isEmpty()) { - Pixmap comb = XCreatePixmap(d->dpy, d->hd, sw, sh, 1); - GC cgc = XCreateGC(d->dpy, comb, 0, 0); - XSetForeground(d->dpy, cgc, 0); - XFillRectangle(d->dpy, comb, cgc, 0, 0, sw, sh); - QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn); - XSetClipRectangles(d->dpy, cgc, -x, -y, rects.data(), rects.size(), Unsorted); - XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), comb, cgc, sx, sy, sw, sh, 0, 0); - XFreeGC(d->dpy, cgc); - - XSetClipMask(d->dpy, d->gc, comb); - XSetClipOrigin(d->dpy, d->gc, x, y); - XFreePixmap(d->dpy, comb); - } else { - XSetClipMask(d->dpy, d->gc, qt_x11PixmapHandle(pixmap)); - XSetClipOrigin(d->dpy, d->gc, x - sx, y - sy); - } - - if (mono_dst) { - XSetForeground(d->dpy, d->gc, qGray(d->cpen.color().rgb()) > 127 ? 0 : 1); - } else { - QXcbColormap cmap = QXcbColormap::instance(d->scrn); - XSetForeground(d->dpy, d->gc, cmap.pixel(d->cpen.color())); - } - XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh); - restore_clip = true; - } else if (mono_dst && !mono_src) { - QBitmap bitmap = QBitmap::fromPixmap(pixmap); - XCopyArea(d->dpy, qt_x11PixmapHandle(bitmap), d->hd, d->gc, sx, sy, sw, sh, x, y); - } else { - XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), d->hd, d->gc, sx, sy, sw, sh, x, y); - } - - if (d->pdev->devType() == QInternal::Pixmap) { - const QPixmap *px = static_cast<const QPixmap*>(d->pdev); - Pixmap src_mask = static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask; - Pixmap dst_mask = static_cast<QX11PlatformPixmap*>(px->handle())->x11_mask; - if (dst_mask) { - GC cgc = XCreateGC(d->dpy, dst_mask, 0, 0); - XSetClipOrigin(d->dpy, cgc, x, y); - XSetClipMask(d->dpy, cgc, src_mask); - if (src_mask) { // copy src mask into dst mask - XCopyArea(d->dpy, src_mask, dst_mask, cgc, sx, sy, sw, sh, x, y); - } else { // no src mask, but make sure the area copied is opaque in dest - XSetBackground(d->dpy, cgc, 0); - XSetForeground(d->dpy, cgc, 1); - XFillRectangle(d->dpy, dst_mask, cgc, x, y, sw, sh); - } - XFreeGC(d->dpy, cgc); - } - } - - if (restore_clip) { - XSetClipOrigin(d->dpy, d->gc, 0, 0); - QList<XRectangle> rects = qt_region_to_xrectangles(d->crgn); - if (rects.isEmpty()) - XSetClipMask(d->dpy, d->gc, XNone); - else - XSetClipRectangles(d->dpy, d->gc, 0, 0, rects.data(), rects.size(), Unsorted); - } -} - -void QX11PaintEngine::updateMatrix(const QTransform &mtx) -{ - Q_D(QX11PaintEngine); - d->txop = mtx.type(); - d->matrix = mtx; - - d->has_complex_xform = (d->txop > QTransform::TxTranslate); - - extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); - bool scaling = qt_scaleForTransform(d->matrix, &d->xform_scale); - d->has_scaling_xform = scaling && d->xform_scale != 1.0; - d->has_non_scaling_xform = scaling && d->xform_scale == 1.0; -} - -/* - NB! the clip region is expected to be in dev coordinates -*/ -void QX11PaintEngine::updateClipRegion_dev(const QRegion &clipRegion, Qt::ClipOperation op) -{ - Q_D(QX11PaintEngine); - QRegion sysClip = d->use_sysclip ? systemClip() : QRegion(); - if (op == Qt::NoClip) { - d->has_clipping = false; - d->crgn = sysClip; - if (!sysClip.isEmpty()) { - x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, sysClip); - } else { - x11ClearClipRegion(d->dpy, d->gc, d->gc_brush, d->picture); - } - return; - } - - switch (op) { - case Qt::IntersectClip: - if (d->has_clipping) { - d->crgn &= clipRegion; - break; - } - // fall through - case Qt::ReplaceClip: - if (!sysClip.isEmpty()) - d->crgn = clipRegion.intersected(sysClip); - else - d->crgn = clipRegion; - break; -// case Qt::UniteClip: -// d->crgn |= clipRegion; -// if (!sysClip.isEmpty()) -// d->crgn = d->crgn.intersected(sysClip); -// break; - default: - break; - } - d->has_clipping = true; - x11SetClipRegion(d->dpy, d->gc, d->gc_brush, d->picture, d->crgn); -} - -void QX11PaintEngine::updateFont(const QFont &) -{ -} - -Drawable QX11PaintEngine::handle() const -{ - Q_D(const QX11PaintEngine); - Q_ASSERT(isActive()); - Q_ASSERT(d->hd); - return d->hd; -} - -extern void qt_draw_tile(QPaintEngine *, qreal, qreal, qreal, qreal, const QPixmap &, - qreal, qreal); - -void QX11PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &p) -{ - int x = qRound(r.x()); - int y = qRound(r.y()); - int w = qRound(r.width()); - int h = qRound(r.height()); - int sx = qRound(p.x()); - int sy = qRound(p.y()); - - bool mono_src = pixmap.depth() == 1; - Q_D(QX11PaintEngine); - - if ((d->xinfo && d->xinfo->screen() != qt_x11Info(pixmap).screen()) - || (qt_x11Info(pixmap).screen() != DefaultScreen(QXcbX11Info::display()))) { - QPixmap* p = const_cast<QPixmap *>(&pixmap); - qt_x11SetScreen(*p, d->xinfo ? d->xinfo->screen() : DefaultScreen(QXcbX11Info::display())); - } - - qt_x11SetDefaultScreen(qt_x11Info(pixmap).screen()); - -#if QT_CONFIG(xrender) - if (X11->use_xrender && d->picture && qt_x11PictureHandle(pixmap)) { - const int numTiles = (w / pixmap.width()) * (h / pixmap.height()); - if (numTiles < 100) { - // this is essentially qt_draw_tile(), inlined for - // the XRenderComposite call - int yPos, xPos, drawH, drawW, yOff, xOff; - yPos = y; - yOff = sy; - while (yPos < y + h) { - drawH = pixmap.height() - yOff; // Cropping first row - if (yPos + drawH > y + h) // Cropping last row - drawH = y + h - yPos; - xPos = x; - xOff = sx; - while (xPos < x + w) { - drawW = pixmap.width() - xOff; // Cropping first column - if (xPos + drawW > x + w) // Cropping last column - drawW = x + w - xPos; - if (mono_src) { - qt_render_bitmap(d->dpy, d->scrn, qt_x11PictureHandle(pixmap), d->picture, - xOff, yOff, xPos, yPos, drawW, drawH, d->cpen); - } else { - XRenderComposite(d->dpy, d->composition_mode, - qt_x11PictureHandle(pixmap), XNone, d->picture, - xOff, yOff, 0, 0, xPos, yPos, drawW, drawH); - } - xPos += drawW; - xOff = 0; - } - yPos += drawH; - yOff = 0; - } - } else { - w = qMin(w, d->pdev->width() - x); - h = qMin(h, d->pdev->height() - y); - if (w <= 0 || h <= 0) - return; - - const int pw = w + sx; - const int ph = h + sy; - QPixmap pm(pw, ph); - if (pixmap.hasAlpha() || mono_src) - pm.fill(Qt::transparent); - - const int mode = pixmap.hasAlpha() ? PictOpOver : PictOpSrc; - const ::Picture pmPicture = qt_x11PictureHandle(pm); - - // first tile - XRenderComposite(d->dpy, mode, - qt_x11PictureHandle(pixmap), XNone, pmPicture, - 0, 0, 0, 0, 0, 0, qMin(pw, pixmap.width()), qMin(ph, pixmap.height())); - - // first row of tiles - int xPos = pixmap.width(); - const int sh = qMin(ph, pixmap.height()); - while (xPos < pw) { - const int sw = qMin(xPos, pw - xPos); - XRenderComposite(d->dpy, mode, - pmPicture, XNone, pmPicture, - 0, 0, 0, 0, xPos, 0, sw, sh); - xPos *= 2; - } - - // remaining rows - int yPos = pixmap.height(); - const int sw = pw; - while (yPos < ph) { - const int sh = qMin(yPos, ph - yPos); - XRenderComposite(d->dpy, mode, - pmPicture, XNone, pmPicture, - 0, 0, 0, 0, 0, yPos, sw, sh); - yPos *= 2; - } - - // composite - if (mono_src) - qt_render_bitmap(d->dpy, d->scrn, pmPicture, d->picture, - sx, sy, x, y, w, h, d->cpen); - else - XRenderComposite(d->dpy, d->composition_mode, - pmPicture, XNone, d->picture, - sx, sy, 0, 0, x, y, w, h); - } - } else -#endif // QT_CONFIG(xrender) - if (pixmap.depth() > 1 && !static_cast<QX11PlatformPixmap*>(pixmap.handle())->x11_mask) { - XSetTile(d->dpy, d->gc, qt_x11PixmapHandle(pixmap)); - XSetFillStyle(d->dpy, d->gc, FillTiled); - XSetTSOrigin(d->dpy, d->gc, x-sx, y-sy); - XFillRectangle(d->dpy, d->hd, d->gc, x, y, w, h); - XSetTSOrigin(d->dpy, d->gc, 0, 0); - XSetFillStyle(d->dpy, d->gc, FillSolid); - } else { - qt_draw_tile(this, x, y, w, h, pixmap, sx, sy); - } -} - -bool QX11PaintEngine::drawCachedGlyphs(const QTransform &transform, const QTextItemInt &ti) -{ -#if QT_CONFIG(xrender) - Q_D(QX11PaintEngine); - Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype); - - if (!X11->use_xrender) - return false; - - QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine); - QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform); - - if (!set || set->outline_drawing) - return false; - - QFontEngine::GlyphFormat glyphFormat = QXRenderGlyphCache::glyphFormatForDepth(ft, d->pdev_depth); - - QXRenderGlyphCache *cache = static_cast<QXRenderGlyphCache *>(ft->glyphCache(set, glyphFormat, transform)); - if (!cache) { - cache = new QXRenderGlyphCache(QXcbX11Info(), glyphFormat, transform); - ft->setGlyphCache(set, cache); - } - - return cache->draw(X11->getSolidFill(d->scrn, d->cpen.color()), d->picture, transform, ti); -#else // !QT_CONFIG(xrender) - return false; -#endif // QT_CONFIG(xrender) -} - -void QX11PaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) -{ - Q_D(QX11PaintEngine); - const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - - switch (ti.fontEngine->type()) { - case QFontEngine::TestFontEngine: - case QFontEngine::Box: - d->drawBoxTextItem(p, ti); - break; -#if QT_CONFIG(fontconfig) - case QFontEngine::Freetype: - drawFreetype(p, ti); - break; -#endif - default: - Q_ASSERT(false); - } -} - -#if QT_CONFIG(fontconfig) -static bool path_for_glyphs(QPainterPath *path, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &positions, - const QFontEngineFT *ft) -{ - bool result = true; - *path = QPainterPath(); - path->setFillRule(Qt::WindingFill); - ft->lockFace(); - int i = 0; - while (i < glyphs.size()) { - QFontEngineFT::Glyph *glyph = ft->loadGlyph(glyphs[i], QFixedPoint(), QFontEngineFT::Format_Mono); - // #### fix case where we don't get a glyph - if (!glyph || glyph->format != QFontEngineFT::Format_Mono) { - result = false; - break; - } - - int n = 0; - int h = glyph->height; - int xp = qRound(positions[i].x); - int yp = qRound(positions[i].y); - - xp += glyph->x; - yp += -glyph->y + glyph->height; - int pitch = ((glyph->width + 31) & ~31) >> 3; - - uchar *src = glyph->data; - while (h--) { - for (int x = 0; x < glyph->width; ++x) { - bool set = src[x >> 3] & (0x80 >> (x & 7)); - if (set) { - QRect r(xp + x, yp - h, 1, 1); - while (x+1 < glyph->width && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7))) { - ++x; - r.setRight(r.right()+1); - } - - path->addRect(r); - ++n; - } - } - src += pitch; - } - ++i; - } - ft->unlockFace(); - return result; -} - -void QX11PaintEngine::drawFreetype(const QPointF &p, const QTextItemInt &ti) -{ - Q_D(QX11PaintEngine); - - if (!ti.glyphs.numGlyphs) - return; - - if (!d->cpen.isSolid()) { - QPaintEngine::drawTextItem(p, ti); - return; - } - - const bool xrenderPath = (X11->use_xrender - && !(d->pdev->devType() == QInternal::Pixmap - && static_cast<const QPixmap *>(d->pdev)->handle()->pixelType() == QPlatformPixmap::BitmapType)); - - if (xrenderPath) { - QTransform transform = d->matrix; - transform.translate(p.x(), p.y()); - - if (drawCachedGlyphs(transform, ti)) - return; - } - - QTransform transform; - transform.translate(p.x(), p.y()); - - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - ti.fontEngine->getGlyphPositions(ti.glyphs, transform, ti.flags, glyphs, positions); - - if (glyphs.count() == 0) - return; - - QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine); - QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform); - QPainterPath path; - - if (!set || set->outline_drawing || !path_for_glyphs(&path, glyphs, positions, ft)) { - QPaintEngine::drawTextItem(p, ti); - return; - } - - if (path.elementCount() <= 1) - return; - - Q_ASSERT((path.elementCount() % 5) == 0); - if (d->txop >= QTransform::TxScale) { - painter()->save(); - painter()->setBrush(d->cpen.brush()); - painter()->setPen(Qt::NoPen); - painter()->drawPath(path); - painter()->restore(); - return; - } - - const int rectcount = 256; - XRectangle rects[rectcount]; - int num_rects = 0; - - QPoint delta(qRound(d->matrix.dx()), qRound(d->matrix.dy())); - QRect clip(d->polygonClipper.boundingRect()); - for (int i=0; i < path.elementCount(); i+=5) { - int x = qRound(path.elementAt(i).x); - int y = qRound(path.elementAt(i).y); - int w = qRound(path.elementAt(i+1).x) - x; - int h = qRound(path.elementAt(i+2).y) - y; - - QRect rect = QRect(x + delta.x(), y + delta.y(), w, h); - rect = rect.intersected(clip); - if (rect.isEmpty()) - continue; - - rects[num_rects].x = short(rect.x()); - rects[num_rects].y = short(rect.y()); - rects[num_rects].width = ushort(rect.width()); - rects[num_rects].height = ushort(rect.height()); - ++num_rects; - if (num_rects == rectcount) { - XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects); - num_rects = 0; - } - } - if (num_rects > 0) - XFillRectangles(d->dpy, d->hd, d->gc, rects, num_rects); -} -#endif // QT_CONFIG(fontconfig) - -#if QT_CONFIG(xrender) -QXRenderGlyphCache::QXRenderGlyphCache(QXcbX11Info x, QFontEngine::GlyphFormat format, const QTransform &matrix) - : QFontEngineGlyphCache(format, matrix) - , xinfo(x) - , gset(XNone) -{} - -QXRenderGlyphCache::~QXRenderGlyphCache() -{ - if (gset != XNone) - XRenderFreeGlyphSet(xinfo.display(), gset); -} - -bool QXRenderGlyphCache::addGlyphs(const QTextItemInt &ti, - const QVarLengthArray<glyph_t> &glyphs, - const QVarLengthArray<QFixedPoint> &positions) -{ - Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype); - - QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine); - QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(transform()); - - XGlyphInfo xglyphinfo; - - for (int i = 0; i < glyphs.size(); ++i) { - const QFixed sppx = ft->subPixelPositionForX(positions[i].x); - const QFixedPoint spp(sppx, 0); - QFontEngineFT::Glyph *glyph = set->getGlyph(glyphs[i], spp); - Glyph xglyphid = qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyphs[i], spp)); - - if (glyph && glyph->format == glyphFormat()) { - if (cachedGlyphs.contains(xglyphid)) { - continue; - } else { - set->setGlyph(glyphs[i], spp, nullptr); - delete glyph; - glyph = 0; - } - } - - glyph = ft->loadGlyphFor(glyphs[i], spp, glyphFormat(), transform(), QColor()); - - if (glyph == 0 || glyph->format != glyphFormat()) - return false; - - if (glyph->format == QFontEngine::Format_Mono) { - // Must convert bitmap from msb to lsb bit order - QImage img(glyph->data, glyph->width, glyph->height, QImage::Format_Mono); - img = img.convertToFormat(QImage::Format_MonoLSB); - memcpy(glyph->data, img.constBits(), static_cast<size_t>(img.sizeInBytes())); - } - - set->setGlyph(glyphs[i], spp, glyph); - Q_ASSERT(glyph->data || glyph->width == 0 || glyph->height == 0); - - xglyphinfo.width = glyph->width; - xglyphinfo.height = glyph->height; - xglyphinfo.x = -glyph->x; - xglyphinfo.y = glyph->y; - xglyphinfo.xOff = glyph->advance; - xglyphinfo.yOff = 0; - - XRenderAddGlyphs(xinfo.display(), glyphSet(), &xglyphid, &xglyphinfo, 1, (const char *) glyph->data, glyphBufferSize(*glyph)); - cachedGlyphs.insert(xglyphid); - } - - return true; -} - -bool QXRenderGlyphCache::draw(Drawable src, Drawable dst, const QTransform &matrix, const QTextItemInt &ti) -{ - Q_ASSERT(ti.fontEngine->type() == QFontEngine::Freetype); - - if (ti.glyphs.numGlyphs == 0) - return true; - - QFontEngineFT *ft = static_cast<QFontEngineFT *>(ti.fontEngine); - QFontEngineFT::QGlyphSet *set = ft->loadGlyphSet(matrix); - - QVarLengthArray<glyph_t> glyphs; - QVarLengthArray<QFixedPoint> positions; - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - - if (glyphs.isEmpty()) - return true; - - if (!addGlyphs(ti, glyphs, positions)) - return false; - - QVarLengthArray<unsigned int> chars(glyphs.size()); - - for (int i = 0; i < glyphs.size(); ++i) - chars[i] = glyphId(glyphs[i], ft->subPixelPositionForX(positions[i].x)); - - int i = 0; - while (i < glyphs.size() && !isValidCoordinate(positions[i])) - ++i; - - if (i >= glyphs.size()) - return true; - - QFixed xp = positions[i].x; - QFixed yp = positions[i].y; - QFixed offs = QFixed::fromReal(aliasedCoordinateDelta); - - XGlyphElt32 elt; - elt.glyphset = gset; - elt.chars = &chars[i]; - elt.nchars = 1; - elt.xOff = qRound(xp + offs); - elt.yOff = qRound(yp + offs); - - ++i; - - for (; i < glyphs.size(); ++i) { - if (!isValidCoordinate(positions[i])) - break; - - const QFixed sppx = ft->subPixelPositionForX(positions[i].x); - const QFixedPoint spp(sppx, 0); - QFontEngineFT::Glyph *g = set->getGlyph(glyphs[i], spp); - - if (g - && positions[i].x == xp + g->advance - && positions[i].y == yp - && elt.nchars < 253 // don't draw more than 253 characters as some X servers - // hang with it - ) { - elt.nchars++; - xp += g->advance; - } else { - xp = positions[i].x; - yp = positions[i].y; - - XRenderCompositeText32(xinfo.display(), PictOpOver, src, dst, - renderPictFormat(), 0, 0, 0, 0, - &elt, 1); - elt.chars = &chars[i]; - elt.nchars = 1; - elt.xOff = qRound(xp + offs); - elt.yOff = qRound(yp + offs); - } - } - - XRenderCompositeText32(xinfo.display(), PictOpOver, src, dst, - renderPictFormat(), 0, 0, 0, 0, &elt, 1); - - return true; -} - -GlyphSet QXRenderGlyphCache::glyphSet() -{ - if (gset == XNone) - gset = XRenderCreateGlyphSet(xinfo.display(), renderPictFormat()); - - Q_ASSERT(gset != XNone); - return gset; -} - -int QXRenderGlyphCache::glyphBufferSize(const QFontEngineFT::Glyph &glyph) const -{ - int pitch = 0; - - switch (glyphFormat()) { - case QFontEngine::Format_Mono: - pitch = ((glyph.width + 31) & ~31) >> 3; - break; - case QFontEngine::Format_A8: - pitch = (glyph.width + 3) & ~3; - break; - default: - pitch = glyph.width * 4; - break; - } - - return pitch * glyph.height; -} - -QImage::Format QXRenderGlyphCache::imageFormat() const -{ - switch (glyphFormat()) { - case QFontEngine::Format_None: - Q_UNREACHABLE(); - break; - case QFontEngine::Format_Mono: - return QImage::Format_Mono; - break; - case QFontEngine::Format_A8: - return QImage::Format_Alpha8; - break; - case QFontEngine::Format_A32: - case QFontEngine::Format_ARGB: - return QImage::Format_ARGB32_Premultiplied; - break; - } - - Q_UNREACHABLE(); -} - -const XRenderPictFormat *QXRenderGlyphCache::renderPictFormat() const -{ - switch (glyphFormat()) { - case QFontEngine::Format_None: - Q_UNREACHABLE(); - break; - case QFontEngine::Format_Mono: - return XRenderFindStandardFormat(xinfo.display(), PictStandardA1); - break; - case QFontEngine::Format_A8: - return XRenderFindStandardFormat(xinfo.display(), PictStandardA8); - break; - case QFontEngine::Format_A32: - case QFontEngine::Format_ARGB: - return XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32); - break; - } - - Q_UNREACHABLE(); -} - -QFontEngine::GlyphFormat QXRenderGlyphCache::glyphFormatForDepth(QFontEngine *fontEngine, int depth) -{ - QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat; - - if (glyphFormat == QFontEngine::Format_None) { - switch (depth) { - case 32: - glyphFormat = QFontEngine::Format_ARGB; - break; - case 24: - glyphFormat = QFontEngine::Format_A32; - break; - case 1: - glyphFormat = QFontEngine::Format_Mono; - break; - default: - glyphFormat = QFontEngine::Format_A8; - break; - } - } - - return glyphFormat; -} - -Glyph QXRenderGlyphCache::glyphId(glyph_t glyph, QFixed subPixelPosition) -{ - return qHash(QFontEngineFT::GlyphAndSubPixelPosition(glyph, QFixedPoint(subPixelPosition, 0))); -} - -bool QXRenderGlyphCache::isValidCoordinate(const QFixedPoint &fp) -{ - enum { t_min = SHRT_MIN, t_max = SHRT_MAX }; - return (fp.x < t_min || fp.x > t_max || fp.y < t_min || fp.y > t_max) ? false : true; -} -#endif // QT_CONFIG(xrender) - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h deleted file mode 100644 index bcbf84682c6..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11_p.h +++ /dev/null @@ -1,86 +0,0 @@ -// 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 - -#pragma once - -#include <QtGui/QPaintEngine> - -typedef unsigned long XID; -typedef XID Drawable; -typedef struct _XGC *GC; - -QT_BEGIN_NAMESPACE - -extern "C" { -Drawable qt_x11Handle(const QPaintDevice *pd); -GC qt_x11_get_pen_gc(QPainter *); -GC qt_x11_get_brush_gc(QPainter *); -} - -class QX11PaintEnginePrivate; -class QX11PaintEngine : public QPaintEngine -{ - Q_DECLARE_PRIVATE(QX11PaintEngine) -public: - QX11PaintEngine(); - ~QX11PaintEngine(); - - bool begin(QPaintDevice *pdev) override; - bool end() override; - - void updateState(const QPaintEngineState &state) override; - - void updatePen(const QPen &pen); - void updateBrush(const QBrush &brush, const QPointF &pt); - void updateRenderHints(QPainter::RenderHints hints); - void updateFont(const QFont &font); - void updateMatrix(const QTransform &matrix); - void updateClipRegion_dev(const QRegion ®ion, Qt::ClipOperation op); - - void drawLines(const QLine *lines, int lineCount) override; - void drawLines(const QLineF *lines, int lineCount) override; - - void drawRects(const QRect *rects, int rectCount) override; - void drawRects(const QRectF *rects, int rectCount) override; - - void drawPoints(const QPoint *points, int pointCount) override; - void drawPoints(const QPointF *points, int pointCount) override; - - void drawEllipse(const QRect &r) override; - void drawEllipse(const QRectF &r) override; - - virtual void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override; - inline void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) override - { QPaintEngine::drawPolygon(points, pointCount, mode); } - - void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override; - void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) override; - void drawPath(const QPainterPath &path) override; - void drawTextItem(const QPointF &p, const QTextItem &textItem) override; - void drawImage(const QRectF &r, const QImage &img, const QRectF &sr, - Qt::ImageConversionFlags flags = Qt::AutoColor) override; - - virtual Drawable handle() const; - inline Type type() const override { return QPaintEngine::X11; } - - QPainter::RenderHints supportedRenderHints() const; - -protected: - QX11PaintEngine(QX11PaintEnginePrivate &dptr); - -#if QT_CONFIG(fontconfig) - void drawFreetype(const QPointF &p, const QTextItemInt &ti); - bool drawCachedGlyphs(const QTransform &transform, const QTextItemInt &ti); -#endif // QT_CONFIG(fontconfig) - - friend class QPixmap; - friend class QFontEngineBox; - friend GC qt_x11_get_pen_gc(QPainter *); - friend GC qt_x11_get_brush_gc(QPainter *); - -private: - Q_DISABLE_COPY_MOVE(QX11PaintEngine) -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp deleted file mode 100644 index b47bd3f5dcc..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp +++ /dev/null @@ -1,2087 +0,0 @@ -// 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 - -#include <QGuiApplication> - -#include <private/qdrawhelper_p.h> -#include <private/qimage_p.h> -#include <private/qimagepixmapcleanuphooks_p.h> - -#include "qxcbnativepainting.h" -#include "qpixmap_x11_p.h" -#include "qcolormap_x11_p.h" -#include "qpaintengine_x11_p.h" - -QT_BEGIN_NAMESPACE - -#if QT_POINTER_SIZE == 8 // 64-bit versions - -Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - quint64 t = (((quint64(x)) | ((quint64(x)) << 24)) & 0x00ff00ff00ff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080) >> 8; - t &= 0x000000ff00ff00ff; - return (uint(t)) | (uint(t >> 24)) | (a << 24); -} - -#else // 32-bit versions - -Q_ALWAYS_INLINE uint PREMUL(uint x) { - uint a = x >> 24; - uint t = (x & 0xff00ff) * a; - t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; - t &= 0xff00ff; - - x = ((x >> 8) & 0xff) * a; - x = (x + ((x >> 8) & 0xff) + 0x80); - x &= 0xff00; - x |= t | (a << 24); - return x; -} -#endif - - - -struct QXImageWrapper -{ - XImage *xi; -}; - -QPixmap qt_toX11Pixmap(const QImage &image) -{ - QPlatformPixmap *data = - new QX11PlatformPixmap(image.depth() == 1 - ? QPlatformPixmap::BitmapType - : QPlatformPixmap::PixmapType); - - data->fromImage(image, Qt::AutoColor); - - return QPixmap(data); -} - -QPixmap qt_toX11Pixmap(const QPixmap &pixmap) -{ - if (pixmap.isNull()) - return QPixmap(); - - if (QPixmap(pixmap).data_ptr()->classId() == QPlatformPixmap::X11Class) - return pixmap; - - return qt_toX11Pixmap(pixmap.toImage()); -} - -// For thread-safety: -// image->data does not belong to X11, so we must free it ourselves. - -inline static void qSafeXDestroyImage(XImage *x) -{ - if (x->data) { - free(x->data); - x->data = 0; - } - XDestroyImage(x); -} - -QBitmap QX11PlatformPixmap::mask_to_bitmap(int screen) const -{ - if (!x11_mask) - return QBitmap(); - qt_x11SetDefaultScreen(screen); - QBitmap bm(w, h); - QX11PlatformPixmap *that = qt_x11Pixmap(bm); - const QXcbX11Info *x = that->x11_info(); - GC gc = XCreateGC(x->display(), that->handle(), 0, 0); - XCopyArea(x->display(), x11_mask, that->handle(), gc, 0, 0, - that->width(), that->height(), 0, 0); - XFreeGC(x->display(), gc); - return bm; -} - -void QX11PlatformPixmap::bitmapFromImage(const QImage &image) -{ - w = image.width(); - h = image.height(); - d = 1; - is_null = (w <= 0 || h <= 0); - hd = createBitmapFromImage(image); -#if QT_CONFIG(xrender) - if (X11->use_xrender) - picture = XRenderCreatePicture(xinfo.display(), hd, - XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0); -#endif // QT_CONFIG(xrender) -} - -bool QX11PlatformPixmap::canTakeQImageFromXImage(const QXImageWrapper &xiWrapper) const -{ - XImage *xi = xiWrapper.xi; - - if (xi->format != ZPixmap) - return false; - - // ARGB32_Premultiplied - if (picture && depth() == 32) - return true; - - // RGB32 - if (depth() == 24 && xi->bits_per_pixel == 32 && xi->red_mask == 0xff0000 - && xi->green_mask == 0xff00 && xi->blue_mask == 0xff) - return true; - - // RGB16 - if (depth() == 16 && xi->bits_per_pixel == 16 && xi->red_mask == 0xf800 - && xi->green_mask == 0x7e0 && xi->blue_mask == 0x1f) - return true; - - return false; -} - -QImage QX11PlatformPixmap::takeQImageFromXImage(const QXImageWrapper &xiWrapper) const -{ - XImage *xi = xiWrapper.xi; - - QImage::Format format = QImage::Format_ARGB32_Premultiplied; - if (depth() == 24) - format = QImage::Format_RGB32; - else if (depth() == 16) - format = QImage::Format_RGB16; - - QImage image((uchar *)xi->data, xi->width, xi->height, xi->bytes_per_line, format); - image.setDevicePixelRatio(devicePixelRatio()); - // take ownership - image.data_ptr()->own_data = true; - xi->data = 0; - - // we may have to swap the byte order - if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && xi->byte_order == MSBFirst) - || (QSysInfo::ByteOrder == QSysInfo::BigEndian && xi->byte_order == LSBFirst)) - { - for (int i=0; i < image.height(); i++) { - if (depth() == 16) { - ushort *p = (ushort*)image.scanLine(i); - ushort *end = p + image.width(); - while (p < end) { - *p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff); - p++; - } - } else { - uint *p = (uint*)image.scanLine(i); - uint *end = p + image.width(); - while (p < end) { - *p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000) - | ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff); - p++; - } - } - } - } - - // fix-up alpha channel - if (format == QImage::Format_RGB32) { - QRgb *p = (QRgb *)image.bits(); - for (int y = 0; y < xi->height; ++y) { - for (int x = 0; x < xi->width; ++x) - p[x] |= 0xff000000; - p += xi->bytes_per_line / 4; - } - } - - XDestroyImage(xi); - return image; -} - -XID QX11PlatformPixmap::bitmap_to_mask(const QBitmap &bitmap, int screen) -{ - if (bitmap.isNull()) - return 0; - QBitmap bm = bitmap; - qt_x11SetScreen(bm, screen); - - QX11PlatformPixmap *that = qt_x11Pixmap(bm); - const QXcbX11Info *x = that->x11_info(); - Pixmap mask = XCreatePixmap(x->display(), RootWindow(x->display(), screen), - that->width(), that->height(), 1); - GC gc = XCreateGC(x->display(), mask, 0, 0); - XCopyArea(x->display(), that->handle(), mask, gc, 0, 0, - that->width(), that->height(), 0, 0); - XFreeGC(x->display(), gc); - return mask; -} - -Drawable qt_x11Handle(const QPixmap &pixmap) -{ - if (pixmap.isNull()) - return XNone; - - if (pixmap.handle()->classId() != QPlatformPixmap::X11Class) - return XNone; - - return static_cast<const QX11PlatformPixmap *>(pixmap.handle())->handle(); -} - - -/***************************************************************************** - Internal functions - *****************************************************************************/ - -//extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp - -// Returns position of highest bit set or -1 if none -static int highest_bit(uint v) -{ - int i; - uint b = (uint)1 << 31; - for (i=31; ((b & v) == 0) && i>=0; i--) - b >>= 1; - return i; -} - -// Counts the number of bits set in 'v' -static uint n_bits(uint v) -{ - int i = 0; - while (v) { - v = v & (v - 1); - i++; - } - return i; -} - -static uint *red_scale_table = nullptr; -static uint *green_scale_table = nullptr; -static uint *blue_scale_table = nullptr; - -static void cleanup_scale_tables() -{ - delete[] red_scale_table; - delete[] green_scale_table; - delete[] blue_scale_table; -} - -/* - Could do smart bitshifting, but the "obvious" algorithm only works for - nBits >= 4. This is more robust. -*/ -static void build_scale_table(uint **table, uint nBits) -{ - if (nBits > 7) { - qWarning("build_scale_table: internal error, nBits = %i", nBits); - return; - } - if (!*table) { - static bool firstTable = true; - if (firstTable) { - qAddPostRoutine(cleanup_scale_tables); - firstTable = false; - } - *table = new uint[256]; - } - int maxVal = (1 << nBits) - 1; - int valShift = 8 - nBits; - int i; - for (i = 0 ; i < maxVal + 1 ; i++) - (*table)[i << valShift] = i*255/maxVal; -} - -static int defaultScreen = -1; - -int qt_x11SetDefaultScreen(int screen) -{ - int old = defaultScreen; - defaultScreen = screen; - return old; -} - -void qt_x11SetScreen(QPixmap &pixmap, int screen) -{ - if (pixmap.paintingActive()) { - qWarning("qt_x11SetScreen(): Cannot change screens during painting"); - return; - } - - if (pixmap.isNull()) - return; - - if (pixmap.handle()->classId() != QPlatformPixmap::X11Class) - return; - - if (screen < 0) - screen = QXcbX11Info::appScreen(); - - QX11PlatformPixmap *pm = static_cast<QX11PlatformPixmap *>(pixmap.handle()); - if (screen == pm->xinfo.screen()) - return; // nothing to do - - if (pixmap.isNull()) { - pm->xinfo = QXcbX11Info::fromScreen(screen); - return; - } - -#if 0 - qDebug("qt_x11SetScreen for %p from %d to %d. Size is %d/%d", pm, pm->xinfo.screen(), screen, pm->width(), pm->height()); -#endif - - qt_x11SetDefaultScreen(screen); - pixmap = qt_toX11Pixmap(pixmap.toImage()); -} - -/***************************************************************************** - QPixmap member functions - *****************************************************************************/ - -QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0); -int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0; - -QX11PlatformPixmap::QX11PlatformPixmap(PixelType pixelType) - : QPlatformPixmap(pixelType, X11Class), hd(0), - flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(0), - dpr(1.0), pengine(0) -{} - -QX11PlatformPixmap::~QX11PlatformPixmap() -{ - // Cleanup hooks have to be called before the handles are freed - if (is_cached) { - QImagePixmapCleanupHooks::executePlatformPixmapDestructionHooks(this); - is_cached = false; - } - - release(); -} - -QPlatformPixmap *QX11PlatformPixmap::createCompatiblePlatformPixmap() const -{ - QX11PlatformPixmap *p = new QX11PlatformPixmap(pixelType()); - p->setDevicePixelRatio(devicePixelRatio()); - return p; -} - -void QX11PlatformPixmap::resize(int width, int height) -{ - setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); - - w = width; - h = height; - is_null = (w <= 0 || h <= 0); - - if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) { - xinfo = QXcbX11Info::fromScreen(defaultScreen); - } - - int dd = xinfo.depth(); - - if (qt_x11_preferred_pixmap_depth) - dd = qt_x11_preferred_pixmap_depth; - - bool make_null = w <= 0 || h <= 0; // create null pixmap - d = (pixelType() == BitmapType ? 1 : dd); - if (make_null || d == 0) { - w = 0; - h = 0; - is_null = true; - hd = 0; - picture = 0; - d = 0; - if (!make_null) - qWarning("QPixmap: Invalid pixmap parameters"); - return; - } - hd = XCreatePixmap(xinfo.display(), - RootWindow(xinfo.display(), xinfo.screen()), - w, h, d); -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - XRenderPictFormat *format = d == 1 - ? XRenderFindStandardFormat(xinfo.display(), PictStandardA1) - : XRenderFindVisualFormat(xinfo.display(), (Visual *) xinfo.visual()); - picture = XRenderCreatePicture(xinfo.display(), hd, format, 0, 0); - } -#endif // QT_CONFIG(xrender) -} - -struct QX11AlphaDetector -{ - bool hasAlpha() const { - if (checked) - return has; - // Will implicitly also check format and return quickly for opaque types... - checked = true; - has = image->isNull() ? false : const_cast<QImage *>(image)->data_ptr()->checkForAlphaPixels(); - return has; - } - - bool hasXRenderAndAlpha() const { - if (!X11->use_xrender) - return false; - return hasAlpha(); - } - - QX11AlphaDetector(const QImage *i, Qt::ImageConversionFlags flags) - : image(i), checked(false), has(false) - { - if (flags & Qt::NoOpaqueDetection) { - checked = true; - has = image->hasAlphaChannel(); - } - } - - const QImage *image; - mutable bool checked; - mutable bool has; -}; - -void QX11PlatformPixmap::fromImage(const QImage &img, Qt::ImageConversionFlags flags) -{ - setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); - - w = img.width(); - h = img.height(); - d = img.depth(); - is_null = (w <= 0 || h <= 0); - setDevicePixelRatio(img.devicePixelRatio()); - - if (is_null) { - w = h = 0; - return; - } - - if (defaultScreen >= 0 && defaultScreen != xinfo.screen()) { - xinfo = QXcbX11Info::fromScreen(defaultScreen); - } - - if (pixelType() == BitmapType) { - bitmapFromImage(img); - return; - } - - if (uint(w) >= 32768 || uint(h) >= 32768) { - w = h = 0; - is_null = true; - return; - } - - QX11AlphaDetector alphaCheck(&img, flags); - int dd = alphaCheck.hasXRenderAndAlpha() ? 32 : xinfo.depth(); - - if (qt_x11_preferred_pixmap_depth) - dd = qt_x11_preferred_pixmap_depth; - - QImage image = img; - - // must be monochrome - if (dd == 1 || (flags & Qt::ColorMode_Mask) == Qt::MonoOnly) { - if (d != 1) { - // dither - image = image.convertToFormat(QImage::Format_MonoLSB, flags); - d = 1; - } - } else { // can be both - bool conv8 = false; - if (d > 8 && dd <= 8) { // convert to 8 bit - if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither) - flags = (flags & ~Qt::DitherMode_Mask) - | Qt::PreferDither; - conv8 = true; - } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) { - conv8 = (d == 1); // native depth wanted - } else if (d == 1) { - if (image.colorCount() == 2) { - QRgb c0 = image.color(0); // Auto: convert to best - QRgb c1 = image.color(1); - conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255); - } else { - // eg. 1-color monochrome images (they do exist). - conv8 = true; - } - } - if (conv8) { - image = image.convertToFormat(QImage::Format_Indexed8, flags); - d = 8; - } - } - - if (d == 1 || image.format() > QImage::Format_ARGB32_Premultiplied) { - QImage::Format fmt = QImage::Format_RGB32; - if (alphaCheck.hasXRenderAndAlpha() && d > 1) - fmt = QImage::Format_ARGB32_Premultiplied; - image = image.convertToFormat(fmt, flags); - fromImage(image, Qt::AutoColor); - return; - } - - Display *dpy = xinfo.display(); - Visual *visual = (Visual *)xinfo.visual(); - XImage *xi = nullptr; - bool trucol = (visual->c_class >= TrueColor); - size_t nbytes = image.sizeInBytes(); - uchar *newbits= nullptr; - -#if QT_CONFIG(xrender) - if (alphaCheck.hasXRenderAndAlpha()) { - const QImage &cimage = image; - - d = 32; - - if (QXcbX11Info::appDepth() != d) { - xinfo.setDepth(d); - } - - hd = XCreatePixmap(dpy, RootWindow(dpy, xinfo.screen()), w, h, d); - picture = XRenderCreatePicture(dpy, hd, - XRenderFindStandardFormat(dpy, PictStandardARGB32), 0, 0); - - xi = XCreateImage(dpy, visual, d, ZPixmap, 0, 0, w, h, 32, 0); - Q_CHECK_PTR(xi); - newbits = (uchar *)malloc(xi->bytes_per_line*h); - Q_CHECK_PTR(newbits); - xi->data = (char *)newbits; - - switch (cimage.format()) { - case QImage::Format_Indexed8: { - QList<QRgb> colorTable = cimage.colorTable(); - uint *xidata = (uint *)xi->data; - for (int y = 0; y < h; ++y) { - const uchar *p = cimage.scanLine(y); - for (int x = 0; x < w; ++x) { - const QRgb rgb = colorTable[p[x]]; - const int a = qAlpha(rgb); - if (a == 0xff) - *xidata = rgb; - else - // RENDER expects premultiplied alpha - *xidata = qRgba(qt_div_255(qRed(rgb) * a), - qt_div_255(qGreen(rgb) * a), - qt_div_255(qBlue(rgb) * a), - a); - ++xidata; - } - } - } - break; - case QImage::Format_RGB32: { - uint *xidata = (uint *)xi->data; - for (int y = 0; y < h; ++y) { - const QRgb *p = (const QRgb *) cimage.scanLine(y); - for (int x = 0; x < w; ++x) - *xidata++ = p[x] | 0xff000000; - } - } - break; - case QImage::Format_ARGB32: { - uint *xidata = (uint *)xi->data; - for (int y = 0; y < h; ++y) { - const QRgb *p = (const QRgb *) cimage.scanLine(y); - for (int x = 0; x < w; ++x) { - const QRgb rgb = p[x]; - const int a = qAlpha(rgb); - if (a == 0xff) - *xidata = rgb; - else - // RENDER expects premultiplied alpha - *xidata = qRgba(qt_div_255(qRed(rgb) * a), - qt_div_255(qGreen(rgb) * a), - qt_div_255(qBlue(rgb) * a), - a); - ++xidata; - } - } - - } - break; - case QImage::Format_ARGB32_Premultiplied: { - uint *xidata = (uint *)xi->data; - for (int y = 0; y < h; ++y) { - const QRgb *p = (const QRgb *) cimage.scanLine(y); - memcpy(xidata, p, w*sizeof(QRgb)); - xidata += w; - } - } - break; - default: - Q_ASSERT(false); - } - - if ((xi->byte_order == MSBFirst) != (QSysInfo::ByteOrder == QSysInfo::BigEndian)) { - uint *xidata = (uint *)xi->data; - uint *xiend = xidata + w*h; - while (xidata < xiend) { - *xidata = (*xidata >> 24) - | ((*xidata >> 8) & 0xff00) - | ((*xidata << 8) & 0xff0000) - | (*xidata << 24); - ++xidata; - } - } - - GC gc = XCreateGC(dpy, hd, 0, 0); - XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h); - XFreeGC(dpy, gc); - - qSafeXDestroyImage(xi); - - return; - } -#endif // QT_CONFIG(xrender) - - if (trucol) { // truecolor display - if (image.format() == QImage::Format_ARGB32_Premultiplied) - image = image.convertToFormat(QImage::Format_ARGB32); - - const QImage &cimage = image; - QRgb pix[256]; // pixel translation table - const bool d8 = (d == 8); - const uint red_mask = (uint)visual->red_mask; - const uint green_mask = (uint)visual->green_mask; - const uint blue_mask = (uint)visual->blue_mask; - const int red_shift = highest_bit(red_mask) - 7; - const int green_shift = highest_bit(green_mask) - 7; - const int blue_shift = highest_bit(blue_mask) - 7; - const uint rbits = highest_bit(red_mask) - lowest_bit(red_mask) + 1; - const uint gbits = highest_bit(green_mask) - lowest_bit(green_mask) + 1; - const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1; - - if (d8) { // setup pixel translation - QList<QRgb> ctable = cimage.colorTable(); - for (int i=0; i < cimage.colorCount(); i++) { - int r = qRed (ctable[i]); - int g = qGreen(ctable[i]); - int b = qBlue (ctable[i]); - r = red_shift > 0 ? r << red_shift : r >> -red_shift; - g = green_shift > 0 ? g << green_shift : g >> -green_shift; - b = blue_shift > 0 ? b << blue_shift : b >> -blue_shift; - pix[i] = (b & blue_mask) | (g & green_mask) | (r & red_mask) - | ~(blue_mask | green_mask | red_mask); - } - } - - xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0); - Q_CHECK_PTR(xi); - newbits = (uchar *)malloc(xi->bytes_per_line*h); - Q_CHECK_PTR(newbits); - if (!newbits) // no memory - return; - int bppc = xi->bits_per_pixel; - - bool contig_bits = n_bits(red_mask) == rbits && - n_bits(green_mask) == gbits && - n_bits(blue_mask) == bbits; - bool dither_tc = - // Want it? - (flags & Qt::Dither_Mask) != Qt::ThresholdDither && - (flags & Qt::DitherMode_Mask) != Qt::AvoidDither && - // Need it? - bppc < 24 && !d8 && - // Can do it? (Contiguous bits?) - contig_bits; - - static bool init=false; - static int D[16][16]; - if (dither_tc && !init) { - // I also contributed this code to XV - WWA. - /* - The dither matrix, D, is obtained with this formula: - - D2 = [0 2] - [3 1] - - - D2*n = [4*Dn 4*Dn+2*Un] - [4*Dn+3*Un 4*Dn+1*Un] - */ - int n,i,j; - init=1; - - /* Set D2 */ - D[0][0]=0; - D[1][0]=2; - D[0][1]=3; - D[1][1]=1; - - /* Expand using recursive definition given above */ - for (n=2; n<16; n*=2) { - for (i=0; i<n; i++) { - for (j=0; j<n; j++) { - D[i][j]*=4; - D[i+n][j]=D[i][j]+2; - D[i][j+n]=D[i][j]+3; - D[i+n][j+n]=D[i][j]+1; - } - } - } - init=true; - } - - enum { BPP8, - BPP16_565, BPP16_555, - BPP16_MSB, BPP16_LSB, - BPP24_888, - BPP24_MSB, BPP24_LSB, - BPP32_8888, - BPP32_MSB, BPP32_LSB - } mode = BPP8; - - bool same_msb_lsb = (xi->byte_order == MSBFirst) == (QSysInfo::ByteOrder == QSysInfo::BigEndian); - - if (bppc == 8) // 8 bit - mode = BPP8; - else if (bppc == 16) { // 16 bit MSB/LSB - if (red_shift == 8 && green_shift == 3 && blue_shift == -3 && !d8 && same_msb_lsb) - mode = BPP16_565; - else if (red_shift == 7 && green_shift == 2 && blue_shift == -3 && !d8 && same_msb_lsb) - mode = BPP16_555; - else - mode = (xi->byte_order == LSBFirst) ? BPP16_LSB : BPP16_MSB; - } else if (bppc == 24) { // 24 bit MSB/LSB - if (red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb) - mode = BPP24_888; - else - mode = (xi->byte_order == LSBFirst) ? BPP24_LSB : BPP24_MSB; - } else if (bppc == 32) { // 32 bit MSB/LSB - if (red_shift == 16 && green_shift == 8 && blue_shift == 0 && !d8 && same_msb_lsb) - mode = BPP32_8888; - else - mode = (xi->byte_order == LSBFirst) ? BPP32_LSB : BPP32_MSB; - } else - qFatal("Logic error 3"); - -#define GET_PIXEL \ - uint pixel; \ - if (d8) pixel = pix[*src++]; \ - else { \ - int r = qRed (*p); \ - int g = qGreen(*p); \ - int b = qBlue (*p++); \ - r = red_shift > 0 \ - ? r << red_shift : r >> -red_shift; \ - g = green_shift > 0 \ - ? g << green_shift : g >> -green_shift; \ - b = blue_shift > 0 \ - ? b << blue_shift : b >> -blue_shift; \ - pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask) \ - | ~(blue_mask | green_mask | red_mask); \ - } - -#define GET_PIXEL_DITHER_TC \ - int r = qRed (*p); \ - int g = qGreen(*p); \ - int b = qBlue (*p++); \ - const int thres = D[x%16][y%16]; \ - if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \ - > thres) \ - r += (1<<(8-rbits)); \ - if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \ - > thres) \ - g += (1<<(8-gbits)); \ - if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \ - > thres) \ - b += (1<<(8-bbits)); \ - r = red_shift > 0 \ - ? r << red_shift : r >> -red_shift; \ - g = green_shift > 0 \ - ? g << green_shift : g >> -green_shift; \ - b = blue_shift > 0 \ - ? b << blue_shift : b >> -blue_shift; \ - uint pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask); - -// again, optimized case -// can't be optimized that much :( -#define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask, \ - rbits,gbits,bbits) \ - const int thres = D[x%16][y%16]; \ - int r = qRed (*p); \ - if (r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \ - > thres) \ - r += (1<<(8-rbits)); \ - int g = qGreen(*p); \ - if (g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \ - > thres) \ - g += (1<<(8-gbits)); \ - int b = qBlue (*p++); \ - if (b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \ - > thres) \ - b += (1<<(8-bbits)); \ - uint pixel = ((r red_shift) & red_mask) \ - | ((g green_shift) & green_mask) \ - | ((b blue_shift) & blue_mask); - -#define CYCLE(body) \ - for (int y=0; y<h; y++) { \ - const uchar* src = cimage.scanLine(y); \ - uchar* dst = newbits + xi->bytes_per_line*y; \ - const QRgb* p = (const QRgb *)src; \ - body \ - } - - if (dither_tc) { - switch (mode) { - case BPP16_565: - CYCLE( - quint16* dst16 = (quint16*)dst; - for (int x=0; x<w; x++) { - GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5) - *dst16++ = pixel; - } - ) - break; - case BPP16_555: - CYCLE( - quint16* dst16 = (quint16*)dst; - for (int x=0; x<w; x++) { - GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5) - *dst16++ = pixel; - } - ) - break; - case BPP16_MSB: // 16 bit MSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL_DITHER_TC - *dst++ = (pixel >> 8); - *dst++ = pixel; - } - ) - break; - case BPP16_LSB: // 16 bit LSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL_DITHER_TC - *dst++ = pixel; - *dst++ = pixel >> 8; - } - ) - break; - default: - qFatal("Logic error"); - } - } else { - switch (mode) { - case BPP8: // 8 bit - CYCLE( - Q_UNUSED(p); - for (int x=0; x<w; x++) - *dst++ = pix[*src++]; - ) - break; - case BPP16_565: - CYCLE( - quint16* dst16 = (quint16*)dst; - for (int x = 0; x < w; x++) { - *dst16++ = ((*p >> 8) & 0xf800) - | ((*p >> 5) & 0x7e0) - | ((*p >> 3) & 0x1f); - ++p; - } - ) - break; - case BPP16_555: - CYCLE( - quint16* dst16 = (quint16*)dst; - for (int x=0; x<w; x++) { - *dst16++ = ((*p >> 9) & 0x7c00) - | ((*p >> 6) & 0x3e0) - | ((*p >> 3) & 0x1f); - ++p; - } - ) - break; - case BPP16_MSB: // 16 bit MSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = (pixel >> 8); - *dst++ = pixel; - } - ) - break; - case BPP16_LSB: // 16 bit LSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - } - ) - break; - case BPP24_888: - CYCLE( - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - for (int x=0; x<w; x++) { - *dst++ = qRed (*p); - *dst++ = qGreen(*p); - *dst++ = qBlue (*p++); - } - } else { - for (int x=0; x<w; x++) { - *dst++ = qBlue (*p); - *dst++ = qGreen(*p); - *dst++ = qRed (*p++); - } - } - ) - break; - case BPP24_MSB: // 24 bit MSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = pixel >> 16; - *dst++ = pixel >> 8; - *dst++ = pixel; - } - ) - break; - case BPP24_LSB: // 24 bit LSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - *dst++ = pixel >> 16; - } - ) - break; - case BPP32_8888: - CYCLE( - memcpy(dst, p, w * 4); - ) - break; - case BPP32_MSB: // 32 bit MSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = pixel >> 24; - *dst++ = pixel >> 16; - *dst++ = pixel >> 8; - *dst++ = pixel; - } - ) - break; - case BPP32_LSB: // 32 bit LSB - CYCLE( - for (int x=0; x<w; x++) { - GET_PIXEL - *dst++ = pixel; - *dst++ = pixel >> 8; - *dst++ = pixel >> 16; - *dst++ = pixel >> 24; - } - ) - break; - default: - qFatal("Logic error 2"); - } - } - xi->data = (char *)newbits; - } - - if (d == 8 && !trucol) { // 8 bit pixmap - int pop[256]; // pixel popularity - - if (image.colorCount() == 0) - image.setColorCount(1); - - const QImage &cimage = image; - memset(pop, 0, sizeof(int)*256); // reset popularity array - for (int i = 0; i < h; i++) { // for each scanline... - const uchar* p = cimage.scanLine(i); - const uchar *end = p + w; - while (p < end) // compute popularity - pop[*p++]++; - } - - newbits = (uchar *)malloc(nbytes); // copy image into newbits - Q_CHECK_PTR(newbits); - if (!newbits) // no memory - return; - uchar* p = newbits; - memcpy(p, cimage.bits(), nbytes); // copy image data into newbits - - /* - * The code below picks the most important colors. It is based on the - * diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley. - */ - - struct PIX { // pixel sort element - uchar r,g,b,n; // color + pad - int use; // popularity - int index; // index in colormap - int mindist; - }; - int ncols = 0; - for (int i=0; i< cimage.colorCount(); i++) { // compute number of colors - if (pop[i] > 0) - ncols++; - } - for (int i = cimage.colorCount(); i < 256; i++) // ignore out-of-range pixels - pop[i] = 0; - - // works since we make sure above to have at least - // one color in the image - if (ncols == 0) - ncols = 1; - - PIX pixarr[256]; // pixel array - PIX pixarr_sorted[256]; // pixel array (sorted) - memset(pixarr, 0, ncols*sizeof(PIX)); - PIX *px = &pixarr[0]; - int maxpop = 0; - int maxpix = 0; - uint j = 0; - QList<QRgb> ctable = cimage.colorTable(); - for (int i = 0; i < 256; i++) { // init pixel array - if (pop[i] > 0) { - px->r = qRed (ctable[i]); - px->g = qGreen(ctable[i]); - px->b = qBlue (ctable[i]); - px->n = 0; - px->use = pop[i]; - if (pop[i] > maxpop) { // select most popular entry - maxpop = pop[i]; - maxpix = j; - } - px->index = i; - px->mindist = 1000000; - px++; - j++; - } - } - pixarr_sorted[0] = pixarr[maxpix]; - pixarr[maxpix].use = 0; - - for (int i = 1; i < ncols; i++) { // sort pixels - int minpix = -1, mindist = -1; - px = &pixarr_sorted[i-1]; - int r = px->r; - int g = px->g; - int b = px->b; - int dist; - if ((i & 1) || i<10) { // sort on max distance - for (int j=0; j<ncols; j++) { - px = &pixarr[j]; - if (px->use) { - dist = (px->r - r)*(px->r - r) + - (px->g - g)*(px->g - g) + - (px->b - b)*(px->b - b); - if (px->mindist > dist) - px->mindist = dist; - if (px->mindist > mindist) { - mindist = px->mindist; - minpix = j; - } - } - } - } else { // sort on max popularity - for (int j=0; j<ncols; j++) { - px = &pixarr[j]; - if (px->use) { - dist = (px->r - r)*(px->r - r) + - (px->g - g)*(px->g - g) + - (px->b - b)*(px->b - b); - if (px->mindist > dist) - px->mindist = dist; - if (px->use > mindist) { - mindist = px->use; - minpix = j; - } - } - } - } - pixarr_sorted[i] = pixarr[minpix]; - pixarr[minpix].use = 0; - } - - QXcbColormap cmap = QXcbColormap::instance(xinfo.screen()); - uint pix[256]; // pixel translation table - px = &pixarr_sorted[0]; - for (int i = 0; i < ncols; i++) { // allocate colors - QColor c(px->r, px->g, px->b); - pix[px->index] = cmap.pixel(c); - px++; - } - - p = newbits; - for (size_t i = 0; i < nbytes; i++) { // translate pixels - *p = pix[*p]; - p++; - } - } - - if (!xi) { // X image not created - xi = XCreateImage(dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0); - if (xi->bits_per_pixel == 16) { // convert 8 bpp ==> 16 bpp - ushort *p2; - int p2inc = xi->bytes_per_line/sizeof(ushort); - ushort *newerbits = (ushort *)malloc(xi->bytes_per_line * h); - Q_CHECK_PTR(newerbits); - if (!newerbits) // no memory - return; - uchar* p = newbits; - for (int y = 0; y < h; y++) { // OOPS: Do right byte order!! - p2 = newerbits + p2inc*y; - for (int x = 0; x < w; x++) - *p2++ = *p++; - } - free(newbits); - newbits = (uchar *)newerbits; - } else if (xi->bits_per_pixel != 8) { - qWarning("QPixmap::fromImage: Display not supported " - "(bpp=%d)", xi->bits_per_pixel); - } - xi->data = (char *)newbits; - } - - hd = XCreatePixmap(dpy, - RootWindow(dpy, xinfo.screen()), - w, h, dd); - - GC gc = XCreateGC(dpy, hd, 0, 0); - XPutImage(dpy, hd, gc, xi, 0, 0, 0, 0, w, h); - XFreeGC(dpy, gc); - - qSafeXDestroyImage(xi); - d = dd; - -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - XRenderPictFormat *format = d == 1 - ? XRenderFindStandardFormat(dpy, PictStandardA1) - : XRenderFindVisualFormat(dpy, (Visual *)xinfo.visual()); - picture = XRenderCreatePicture(dpy, hd, format, 0, 0); - } -#endif - - if (alphaCheck.hasAlpha()) { - QBitmap m = QBitmap::fromImage(image.createAlphaMask(flags)); - setMask(m); - } -} - -void QX11PlatformPixmap::copy(const QPlatformPixmap *data, const QRect &rect) -{ - if (data->pixelType() == BitmapType) { - fromImage(data->toImage().copy(rect), Qt::AutoColor); - return; - } - - const QX11PlatformPixmap *x11Data = static_cast<const QX11PlatformPixmap*>(data); - - setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); - - flags &= ~Uninitialized; - xinfo = x11Data->xinfo; - d = x11Data->d; - w = rect.width(); - h = rect.height(); - is_null = (w <= 0 || h <= 0); - hd = XCreatePixmap(xinfo.display(), - RootWindow(xinfo.display(), x11Data->xinfo.screen()), - w, h, d); -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - XRenderPictFormat *format = d == 32 - ? XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32) - : XRenderFindVisualFormat(xinfo.display(), (Visual *)xinfo.visual()); - picture = XRenderCreatePicture(xinfo.display(), hd, format, 0, 0); - } -#endif // QT_CONFIG(xrender) - if (x11Data->x11_mask) { - x11_mask = XCreatePixmap(xinfo.display(), hd, w, h, 1); -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - mask_picture = XRenderCreatePicture(xinfo.display(), x11_mask, - XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0); - XRenderPictureAttributes attrs; - attrs.alpha_map = x11Data->mask_picture; - XRenderChangePicture(xinfo.display(), x11Data->picture, CPAlphaMap, &attrs); - } -#endif - } - -#if QT_CONFIG(xrender) - if (x11Data->picture && x11Data->d == 32) { - XRenderComposite(xinfo.display(), PictOpSrc, - x11Data->picture, 0, picture, - rect.x(), rect.y(), 0, 0, 0, 0, w, h); - } else -#endif - { - GC gc = XCreateGC(xinfo.display(), hd, 0, 0); - XCopyArea(xinfo.display(), x11Data->hd, hd, gc, - rect.x(), rect.y(), w, h, 0, 0); - if (x11Data->x11_mask) { - GC monogc = XCreateGC(xinfo.display(), x11_mask, 0, 0); - XCopyArea(xinfo.display(), x11Data->x11_mask, x11_mask, monogc, - rect.x(), rect.y(), w, h, 0, 0); - XFreeGC(xinfo.display(), monogc); - } - XFreeGC(xinfo.display(), gc); - } -} - -bool QX11PlatformPixmap::scroll(int dx, int dy, const QRect &rect) -{ - GC gc = XCreateGC(xinfo.display(), hd, 0, 0); - XCopyArea(xinfo.display(), hd, hd, gc, - rect.left(), rect.top(), rect.width(), rect.height(), - rect.left() + dx, rect.top() + dy); - XFreeGC(xinfo.display(), gc); - return true; -} - -int QX11PlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const -{ - switch (metric) { - case QPaintDevice::PdmDevicePixelRatio: - return devicePixelRatio(); - break; - case QPaintDevice::PdmDevicePixelRatioScaled: - return devicePixelRatio() * QPaintDevice::devicePixelRatioFScale(); - break; - case QPaintDevice::PdmWidth: - return w; - case QPaintDevice::PdmHeight: - return h; - case QPaintDevice::PdmNumColors: - return 1 << d; - case QPaintDevice::PdmDepth: - return d; - case QPaintDevice::PdmWidthMM: { - const int screen = xinfo.screen(); - const int mm = DisplayWidthMM(xinfo.display(), screen) * w - / DisplayWidth(xinfo.display(), screen); - return mm; - } - case QPaintDevice::PdmHeightMM: { - const int screen = xinfo.screen(); - const int mm = (DisplayHeightMM(xinfo.display(), screen) * h) - / DisplayHeight(xinfo.display(), screen); - return mm; - } - case QPaintDevice::PdmDpiX: - case QPaintDevice::PdmPhysicalDpiX: - return QXcbX11Info::appDpiX(xinfo.screen()); - case QPaintDevice::PdmDpiY: - case QPaintDevice::PdmPhysicalDpiY: - return QXcbX11Info::appDpiY(xinfo.screen()); - default: - qWarning("QX11PlatformPixmap::metric(): Invalid metric"); - return 0; - } -} - -void QX11PlatformPixmap::fill(const QColor &fillColor) -{ - if (fillColor.alpha() != 255) { -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - if (!picture || d != 32) - convertToARGB32(/*preserveContents = */false); - - ::Picture src = X11->getSolidFill(xinfo.screen(), fillColor); - XRenderComposite(xinfo.display(), PictOpSrc, src, 0, picture, - 0, 0, width(), height(), - 0, 0, width(), height()); - } else -#endif - { - QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied); - im.fill(PREMUL(fillColor.rgba())); - release(); - fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither); - } - return; - } - - GC gc = XCreateGC(xinfo.display(), hd, 0, 0); - if (depth() == 1) { - XSetForeground(xinfo.display(), gc, qGray(fillColor.rgb()) > 127 ? 0 : 1); - } else if (X11->use_xrender && d >= 24) { - XSetForeground(xinfo.display(), gc, fillColor.rgba()); - } else { - XSetForeground(xinfo.display(), gc, - QXcbColormap::instance(xinfo.screen()).pixel(fillColor)); - } - XFillRectangle(xinfo.display(), hd, gc, 0, 0, width(), height()); - XFreeGC(xinfo.display(), gc); -} - -QBitmap QX11PlatformPixmap::mask() const -{ - QBitmap mask; -#if QT_CONFIG(xrender) - if (picture && d == 32) { - // #### slow - there must be a better way.. - mask = QBitmap::fromImage(toImage().createAlphaMask()); - } else -#endif - if (d == 1) { - QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this); - mask = QBitmap::fromPixmap(QPixmap(that)); - } else { - mask = mask_to_bitmap(xinfo.screen()); - } - return mask; -} - -void QX11PlatformPixmap::setMask(const QBitmap &newmask) -{ - if (newmask.isNull()) { // clear mask -#if QT_CONFIG(xrender) - if (picture && d == 32) { - QX11PlatformPixmap newData(pixelType()); - newData.resize(w, h); - newData.fill(Qt::black); - XRenderComposite(xinfo.display(), PictOpOver, - picture, 0, newData.picture, - 0, 0, 0, 0, 0, 0, w, h); - release(); - *this = newData; - // the new QX11PlatformPixmap object isn't referenced yet, so - // ref it - ref.ref(); - - // the below is to make sure the QX11PlatformPixmap destructor - // doesn't delete our newly created render picture - newData.hd = 0; - newData.x11_mask = 0; - newData.picture = 0; - newData.mask_picture = 0; - newData.hd2 = 0; - } else -#endif - if (x11_mask) { -#if QT_CONFIG(xrender) - if (picture) { - XRenderPictureAttributes attrs; - attrs.alpha_map = 0; - XRenderChangePicture(xinfo.display(), picture, CPAlphaMap, - &attrs); - } - if (mask_picture) - XRenderFreePicture(xinfo.display(), mask_picture); - mask_picture = 0; -#endif - XFreePixmap(xinfo.display(), x11_mask); - x11_mask = 0; - } - return; - } - -#if QT_CONFIG(xrender) - if (picture && d == 32) { - XRenderComposite(xinfo.display(), PictOpSrc, - picture, qt_x11Pixmap(newmask)->x11PictureHandle(), - picture, 0, 0, 0, 0, 0, 0, w, h); - } else -#endif - if (depth() == 1) { - XGCValues vals; - vals.function = GXand; - GC gc = XCreateGC(xinfo.display(), hd, GCFunction, &vals); - XCopyArea(xinfo.display(), qt_x11Pixmap(newmask)->handle(), hd, gc, 0, 0, - width(), height(), 0, 0); - XFreeGC(xinfo.display(), gc); - } else { - // ##### should or the masks together - if (x11_mask) { - XFreePixmap(xinfo.display(), x11_mask); -#if QT_CONFIG(xrender) - if (mask_picture) - XRenderFreePicture(xinfo.display(), mask_picture); -#endif - } - x11_mask = QX11PlatformPixmap::bitmap_to_mask(newmask, xinfo.screen()); -#if QT_CONFIG(xrender) - if (picture) { - mask_picture = XRenderCreatePicture(xinfo.display(), x11_mask, - XRenderFindStandardFormat(xinfo.display(), PictStandardA1), 0, 0); - XRenderPictureAttributes attrs; - attrs.alpha_map = mask_picture; - XRenderChangePicture(xinfo.display(), picture, CPAlphaMap, &attrs); - } -#endif - } -} - -bool QX11PlatformPixmap::hasAlphaChannel() const -{ - if (picture && d == 32) - return true; - - if (x11_mask && d == 1) - return true; - - return false; -} - -QPixmap QX11PlatformPixmap::transformed(const QTransform &transform, Qt::TransformationMode mode) const -{ - if (mode == Qt::SmoothTransformation || transform.type() >= QTransform::TxProject) { - QImage image = toImage(); - return QPixmap::fromImage(image.transformed(transform, mode)); - } - - uint w = 0; - uint h = 0; // size of target pixmap - uint ws, hs; // size of source pixmap - uchar *dptr; // data in target pixmap - uint dbpl, dbytes; // bytes per line/bytes total - uchar *sptr; // data in original pixmap - int sbpl; // bytes per line in original - int bpp; // bits per pixel - bool depth1 = depth() == 1; - Display *dpy = xinfo.display(); - - ws = width(); - hs = height(); - - QTransform mat(transform.m11(), transform.m12(), transform.m13(), - transform.m21(), transform.m22(), transform.m23(), - 0., 0., 1); - bool complex_xform = false; - - if (mat.type() <= QTransform::TxScale) { - h = qRound(qAbs(mat.m22()) * hs); - w = qRound(qAbs(mat.m11()) * ws); - } else { // rotation or shearing - QPolygonF a(QRectF(0, 0, ws, hs)); - a = mat.map(a); - QRect r = a.boundingRect().toAlignedRect(); - w = r.width(); - h = r.height(); - complex_xform = true; - } - mat = QPixmap::trueMatrix(mat, ws, hs); // true matrix - - bool invertible; - mat = mat.inverted(&invertible); // invert matrix - - if (h == 0 || w == 0 || !invertible - || qAbs(h) >= 32768 || qAbs(w) >= 32768 ) - // error, return null pixmap - return QPixmap(); - - XImage *xi = XGetImage(xinfo.display(), handle(), 0, 0, ws, hs, AllPlanes, - depth1 ? XYPixmap : ZPixmap); - - if (!xi) - return QPixmap(); - - sbpl = xi->bytes_per_line; - sptr = (uchar *)xi->data; - bpp = xi->bits_per_pixel; - - if (depth1) - dbpl = (w+7)/8; - else - dbpl = ((w*bpp+31)/32)*4; - dbytes = dbpl*h; - - dptr = (uchar *)malloc(dbytes); // create buffer for bits - Q_CHECK_PTR(dptr); - if (depth1) // fill with zeros - memset(dptr, 0, dbytes); - else if (bpp == 8) // fill with background color - memset(dptr, WhitePixel(xinfo.display(), xinfo.screen()), dbytes); - else - memset(dptr, 0, dbytes); - - // #define QT_DEBUG_XIMAGE -#if defined(QT_DEBUG_XIMAGE) - qDebug("----IMAGE--INFO--------------"); - qDebug("width............. %d", xi->width); - qDebug("height............ %d", xi->height); - qDebug("xoffset........... %d", xi->xoffset); - qDebug("format............ %d", xi->format); - qDebug("byte order........ %d", xi->byte_order); - qDebug("bitmap unit....... %d", xi->bitmap_unit); - qDebug("bitmap bit order.. %d", xi->bitmap_bit_order); - qDebug("depth............. %d", xi->depth); - qDebug("bytes per line.... %d", xi->bytes_per_line); - qDebug("bits per pixel.... %d", xi->bits_per_pixel); -#endif - - int type; - if (xi->bitmap_bit_order == MSBFirst) - type = QT_XFORM_TYPE_MSBFIRST; - else - type = QT_XFORM_TYPE_LSBFIRST; - int xbpl, p_inc; - if (depth1) { - xbpl = (w+7)/8; - p_inc = dbpl - xbpl; - } else { - xbpl = (w*bpp)/8; - p_inc = dbpl - xbpl; - } - - if (!qt_xForm_helper(mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs)){ - qWarning("QPixmap::transform: display not supported (bpp=%d)",bpp); - QPixmap pm; - free(dptr); - return pm; - } - - qSafeXDestroyImage(xi); - - if (depth1) { // mono bitmap - QBitmap bm = QBitmap::fromData(QSize(w, h), dptr, - BitmapBitOrder(xinfo.display()) == MSBFirst - ? QImage::Format_Mono - : QImage::Format_MonoLSB); - free(dptr); - return bm; - } else { // color pixmap - QX11PlatformPixmap *x11Data = new QX11PlatformPixmap(QPlatformPixmap::PixmapType); - QPixmap pm(x11Data); - x11Data->flags &= ~QX11PlatformPixmap::Uninitialized; - x11Data->xinfo = xinfo; - x11Data->d = d; - x11Data->w = w; - x11Data->h = h; - x11Data->is_null = (w <= 0 || h <= 0); - x11Data->hd = XCreatePixmap(xinfo.display(), - RootWindow(xinfo.display(), xinfo.screen()), - w, h, d); - x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1)); - -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - XRenderPictFormat *format = x11Data->d == 32 - ? XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32) - : XRenderFindVisualFormat(xinfo.display(), (Visual *) x11Data->xinfo.visual()); - x11Data->picture = XRenderCreatePicture(xinfo.display(), x11Data->hd, format, 0, 0); - } -#endif // QT_CONFIG(xrender) - - GC gc = XCreateGC(xinfo.display(), x11Data->hd, 0, 0); - xi = XCreateImage(dpy, (Visual*)x11Data->xinfo.visual(), - x11Data->d, - ZPixmap, 0, (char *)dptr, w, h, 32, 0); - XPutImage(dpy, qt_x11Pixmap(pm)->handle(), gc, xi, 0, 0, 0, 0, w, h); - qSafeXDestroyImage(xi); - XFreeGC(xinfo.display(), gc); - - if (x11_mask) { // xform mask, too - pm.setMask(mask_to_bitmap(xinfo.screen()).transformed(transform)); - } else if (d != 32 && complex_xform) { // need a mask! - QBitmap mask(ws, hs); - mask.fill(Qt::color1); - pm.setMask(mask.transformed(transform)); - } - return pm; - } -} - -QImage QX11PlatformPixmap::toImage() const -{ - return toImage(QRect(0, 0, w, h)); -} - -QImage QX11PlatformPixmap::toImage(const QRect &rect) const -{ - Window root_return; - int x_return; - int y_return; - unsigned int width_return; - unsigned int height_return; - unsigned int border_width_return; - unsigned int depth_return; - - XGetGeometry(xinfo.display(), hd, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); - - QXImageWrapper xiWrapper; - xiWrapper.xi = XGetImage(xinfo.display(), hd, rect.x(), rect.y(), rect.width(), rect.height(), - AllPlanes, (depth() == 1) ? XYPixmap : ZPixmap); - - Q_CHECK_PTR(xiWrapper.xi); - if (!xiWrapper.xi) - return QImage(); - - if (!x11_mask && canTakeQImageFromXImage(xiWrapper)) - return takeQImageFromXImage(xiWrapper); - - QImage image = toImage(xiWrapper, rect); - qSafeXDestroyImage(xiWrapper.xi); - return image; -} - -#if QT_CONFIG(xrender) -static XRenderPictFormat *qt_renderformat_for_depth(const QXcbX11Info &xinfo, int depth) -{ - if (depth == 1) - return XRenderFindStandardFormat(xinfo.display(), PictStandardA1); - else if (depth == 32) - return XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32); - else - return XRenderFindVisualFormat(xinfo.display(), (Visual *)xinfo.visual()); -} -#endif - -Q_GLOBAL_STATIC(QX11PaintEngine, qt_x11_paintengine) - -QPaintEngine *QX11PlatformPixmap::paintEngine() const -{ - QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this); - - if ((flags & Readonly)/* && share_mode == QPixmap::ImplicitlyShared*/) { - // if someone wants to draw onto us, copy the shared contents - // and turn it into a fully fledged QPixmap - ::Pixmap hd_copy = XCreatePixmap(xinfo.display(), RootWindow(xinfo.display(), xinfo.screen()), - w, h, d); -#if QT_CONFIG(xrender) - if (picture && d == 32) { - XRenderPictFormat *format = qt_renderformat_for_depth(xinfo, d); - ::Picture picture_copy = XRenderCreatePicture(xinfo.display(), - hd_copy, format, - 0, 0); - - XRenderComposite(xinfo.display(), PictOpSrc, picture, 0, picture_copy, - 0, 0, 0, 0, 0, 0, w, h); - XRenderFreePicture(xinfo.display(), picture); - that->picture = picture_copy; - } else -#endif - { - GC gc = XCreateGC(xinfo.display(), hd_copy, 0, 0); - XCopyArea(xinfo.display(), hd, hd_copy, gc, 0, 0, w, h, 0, 0); - XFreeGC(xinfo.display(), gc); - } - that->hd = hd_copy; - that->flags &= ~QX11PlatformPixmap::Readonly; - } - - if (qt_x11_paintengine->isActive()) { - if (!that->pengine) - that->pengine = new QX11PaintEngine; - - return that->pengine; - } - - return qt_x11_paintengine(); -} - -qreal QX11PlatformPixmap::devicePixelRatio() const -{ - return dpr; -} - -void QX11PlatformPixmap::setDevicePixelRatio(qreal scaleFactor) -{ - dpr = scaleFactor; -} - -Pixmap QX11PlatformPixmap::x11ConvertToDefaultDepth() -{ -#if QT_CONFIG(xrender) - if (d == xinfo.appDepth() || !X11->use_xrender) - return hd; - if (!hd2) { - hd2 = XCreatePixmap(xinfo.display(), hd, w, h, xinfo.appDepth()); - XRenderPictFormat *format = XRenderFindVisualFormat(xinfo.display(), - (Visual*) xinfo.visual()); - Picture pic = XRenderCreatePicture(xinfo.display(), hd2, format, 0, 0); - XRenderComposite(xinfo.display(), PictOpSrc, picture, - XNone, pic, 0, 0, 0, 0, 0, 0, w, h); - XRenderFreePicture(xinfo.display(), pic); - } - return hd2; -#else - return hd; -#endif -} - -XID QX11PlatformPixmap::createBitmapFromImage(const QImage &image) -{ - QImage img = image.convertToFormat(QImage::Format_MonoLSB); - const QRgb c0 = QColor(Qt::black).rgb(); - const QRgb c1 = QColor(Qt::white).rgb(); - if (img.color(0) == c0 && img.color(1) == c1) { - img.invertPixels(); - img.setColor(0, c1); - img.setColor(1, c0); - } - - char *bits; - uchar *tmp_bits; - int w = img.width(); - int h = img.height(); - int bpl = (w + 7) / 8; - qsizetype ibpl = img.bytesPerLine(); - if (bpl != ibpl) { - tmp_bits = new uchar[bpl*h]; - bits = (char *)tmp_bits; - uchar *p, *b; - int y; - b = tmp_bits; - p = img.scanLine(0); - for (y = 0; y < h; y++) { - memcpy(b, p, bpl); - b += bpl; - p += ibpl; - } - } else { - bits = (char *)img.bits(); - tmp_bits = 0; - } - XID hd = XCreateBitmapFromData(QXcbX11Info::display(), - QXcbX11Info::appRootWindow(), - bits, w, h); - if (tmp_bits) // Avoid purify complaint - delete [] tmp_bits; - return hd; -} - -bool QX11PlatformPixmap::isBackingStore() const -{ - return (flags & IsBackingStore); -} - -void QX11PlatformPixmap::setIsBackingStore(bool on) -{ - if (on) - flags |= IsBackingStore; - else { - flags &= ~IsBackingStore; - } -} - -#if QT_CONFIG(xrender) -void QX11PlatformPixmap::convertToARGB32(bool preserveContents) -{ - if (!X11->use_xrender) - return; - - // Q_ASSERT(count == 1); - if ((flags & Readonly)/* && share_mode == QPixmap::ExplicitlyShared*/) - return; - - Pixmap pm = XCreatePixmap(xinfo.display(), RootWindow(xinfo.display(), xinfo.screen()), - w, h, 32); - Picture p = XRenderCreatePicture(xinfo.display(), pm, - XRenderFindStandardFormat(xinfo.display(), PictStandardARGB32), 0, 0); - if (picture) { - if (preserveContents) - XRenderComposite(xinfo.display(), PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h); - if (!(flags & Readonly)) - XRenderFreePicture(xinfo.display(), picture); - } - if (hd && !(flags & Readonly)) - XFreePixmap(xinfo.display(), hd); - if (x11_mask) { - XFreePixmap(xinfo.display(), x11_mask); - if (mask_picture) - XRenderFreePicture(xinfo.display(), mask_picture); - x11_mask = 0; - mask_picture = 0; - } - hd = pm; - picture = p; - - d = 32; - xinfo.setDepth(32); - - XVisualInfo visinfo; - if (XMatchVisualInfo(xinfo.display(), xinfo.screen(), 32, TrueColor, &visinfo)) - xinfo.setVisual(visinfo.visual); -} -#endif - -void QX11PlatformPixmap::release() -{ - delete pengine; - pengine = 0; - - if (/*!X11*/ QCoreApplication::closingDown()) { - // At this point, the X server will already have freed our resources, - // so there is nothing to do. - return; - } - - if (x11_mask) { -#if QT_CONFIG(xrender) - if (mask_picture) - XRenderFreePicture(xinfo.display(), mask_picture); - mask_picture = 0; -#endif - XFreePixmap(xinfo.display(), x11_mask); - x11_mask = 0; - } - - if (hd) { -#if QT_CONFIG(xrender) - if (picture) { - XRenderFreePicture(xinfo.display(), picture); - picture = 0; - } -#endif // QT_CONFIG(xrender) - - if (hd2) { - XFreePixmap(xinfo.display(), hd2); - hd2 = 0; - } - if (!(flags & Readonly)) - XFreePixmap(xinfo.display(), hd); - hd = 0; - } -} - -QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect &rect) const -{ - XImage *xi = xiWrapper.xi; - - int d = depth(); - Visual *visual = (Visual *)xinfo.visual(); - bool trucol = (visual->c_class >= TrueColor) && d > 1; - - QImage::Format format = QImage::Format_Mono; - if (d > 1 && d <= 8) { - d = 8; - format = QImage::Format_Indexed8; - } - // we could run into the situation where d == 8 AND trucol is true, which can - // cause problems when converting to and from images. in this case, always treat - // the depth as 32... - if (d > 8 || trucol) { - d = 32; - format = QImage::Format_RGB32; - } - - if (d == 1 && xi->bitmap_bit_order == LSBFirst) - format = QImage::Format_MonoLSB; - if (x11_mask && format == QImage::Format_RGB32) - format = QImage::Format_ARGB32; - - QImage image(xi->width, xi->height, format); - image.setDevicePixelRatio(devicePixelRatio()); - if (image.isNull()) // could not create image - return image; - - QImage alpha; - if (x11_mask) { - if (rect.contains(QRect(0, 0, w, h))) - alpha = mask().toImage(); - else - alpha = mask().toImage().copy(rect); - } - bool ale = alpha.format() == QImage::Format_MonoLSB; - - if (trucol) { // truecolor - const uint red_mask = (uint)visual->red_mask; - const uint green_mask = (uint)visual->green_mask; - const uint blue_mask = (uint)visual->blue_mask; - const int red_shift = highest_bit(red_mask) - 7; - const int green_shift = highest_bit(green_mask) - 7; - const int blue_shift = highest_bit(blue_mask) - 7; - - const uint red_bits = n_bits(red_mask); - const uint green_bits = n_bits(green_mask); - const uint blue_bits = n_bits(blue_mask); - - static uint red_table_bits = 0; - static uint green_table_bits = 0; - static uint blue_table_bits = 0; - - if (red_bits < 8 && red_table_bits != red_bits) { - build_scale_table(&red_scale_table, red_bits); - red_table_bits = red_bits; - } - if (blue_bits < 8 && blue_table_bits != blue_bits) { - build_scale_table(&blue_scale_table, blue_bits); - blue_table_bits = blue_bits; - } - if (green_bits < 8 && green_table_bits != green_bits) { - build_scale_table(&green_scale_table, green_bits); - green_table_bits = green_bits; - } - - int r, g, b; - - QRgb *dst; - uchar *src; - uint pixel; - int bppc = xi->bits_per_pixel; - - if (bppc > 8 && xi->byte_order == LSBFirst) - bppc++; - - for (int y = 0; y < xi->height; ++y) { - uchar* asrc = x11_mask ? alpha.scanLine(y) : 0; - dst = (QRgb *)image.scanLine(y); - src = (uchar *)xi->data + xi->bytes_per_line*y; - for (int x = 0; x < xi->width; x++) { - switch (bppc) { - case 8: - pixel = *src++; - break; - case 16: // 16 bit MSB - pixel = src[1] | (uint)src[0] << 8; - src += 2; - break; - case 17: // 16 bit LSB - pixel = src[0] | (uint)src[1] << 8; - src += 2; - break; - case 24: // 24 bit MSB - pixel = src[2] | (uint)src[1] << 8 | (uint)src[0] << 16; - src += 3; - break; - case 25: // 24 bit LSB - pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16; - src += 3; - break; - case 32: // 32 bit MSB - pixel = src[3] | (uint)src[2] << 8 | (uint)src[1] << 16 | (uint)src[0] << 24; - src += 4; - break; - case 33: // 32 bit LSB - pixel = src[0] | (uint)src[1] << 8 | (uint)src[2] << 16 | (uint)src[3] << 24; - src += 4; - break; - default: // should not really happen - x = xi->width; // leave loop - y = xi->height; - pixel = 0; // eliminate compiler warning - qWarning("QPixmap::convertToImage: Invalid depth %d", bppc); - } - if (red_shift > 0) - r = (pixel & red_mask) >> red_shift; - else - r = (pixel & red_mask) << -red_shift; - if (green_shift > 0) - g = (pixel & green_mask) >> green_shift; - else - g = (pixel & green_mask) << -green_shift; - if (blue_shift > 0) - b = (pixel & blue_mask) >> blue_shift; - else - b = (pixel & blue_mask) << -blue_shift; - - if (red_bits < 8) - r = red_scale_table[r]; - if (green_bits < 8) - g = green_scale_table[g]; - if (blue_bits < 8) - b = blue_scale_table[b]; - - if (x11_mask) { - if (ale) { - *dst++ = (asrc[x >> 3] & (1 << (x & 7))) ? qRgba(r, g, b, 0xff) : 0; - } else { - *dst++ = (asrc[x >> 3] & (0x80 >> (x & 7))) ? qRgba(r, g, b, 0xff) : 0; - } - } else { - *dst++ = qRgb(r, g, b); - } - } - } - } else if (xi->bits_per_pixel == d) { // compatible depth - char *xidata = xi->data; // copy each scanline - qsizetype bpl = qMin(image.bytesPerLine(),xi->bytes_per_line); - for (int y=0; y<xi->height; y++) { - memcpy(image.scanLine(y), xidata, bpl); - xidata += xi->bytes_per_line; - } - } else { - /* Typically 2 or 4 bits display depth */ - qWarning("QPixmap::convertToImage: Display not supported (bpp=%d)", - xi->bits_per_pixel); - return QImage(); - } - - if (d == 1) { // bitmap - image.setColorCount(2); - image.setColor(0, qRgb(255,255,255)); - image.setColor(1, qRgb(0,0,0)); - } else if (!trucol) { // pixmap with colormap - uchar *p; - uchar *end; - uchar use[256]; // pixel-in-use table - uchar pix[256]; // pixel translation table - int ncols; - memset(use, 0, 256); - memset(pix, 0, 256); - qsizetype bpl = image.bytesPerLine(); - - if (x11_mask) { // which pixels are used? - for (int i = 0; i < xi->height; i++) { - uchar* asrc = alpha.scanLine(i); - p = image.scanLine(i); - if (ale) { - for (int x = 0; x < xi->width; x++) { - if (asrc[x >> 3] & (1 << (x & 7))) - use[*p] = 1; - ++p; - } - } else { - for (int x = 0; x < xi->width; x++) { - if (asrc[x >> 3] & (0x80 >> (x & 7))) - use[*p] = 1; - ++p; - } - } - } - } else { - for (int i = 0; i < xi->height; i++) { - p = image.scanLine(i); - end = p + bpl; - while (p < end) - use[*p++] = 1; - } - } - ncols = 0; - for (int i = 0; i < 256; i++) { // build translation table - if (use[i]) - pix[i] = ncols++; - } - for (int i = 0; i < xi->height; i++) { // translate pixels - p = image.scanLine(i); - end = p + bpl; - while (p < end) { - *p = pix[*p]; - p++; - } - } - if (x11_mask) { - int trans; - if (ncols < 256) { - trans = ncols++; - image.setColorCount(ncols); // create color table - image.setColor(trans, 0x00000000); - } else { - image.setColorCount(ncols); // create color table - // oh dear... no spare "transparent" pixel. - // use first pixel in image (as good as any). - trans = image.scanLine(0)[0]; - } - for (int i = 0; i < xi->height; i++) { - uchar* asrc = alpha.scanLine(i); - p = image.scanLine(i); - if (ale) { - for (int x = 0; x < xi->width; x++) { - if (!(asrc[x >> 3] & (1 << (x & 7)))) - *p = trans; - ++p; - } - } else { - for (int x = 0; x < xi->width; x++) { - if (!(asrc[x >> 3] & (1 << (7 -(x & 7))))) - *p = trans; - ++p; - } - } - } - } else { - image.setColorCount(ncols); // create color table - } - QList<QColor> colors = QXcbColormap::instance(xinfo.screen()).colormap(); - int j = 0; - for (int i=0; i<colors.size(); i++) { // translate pixels - if (use[i]) - image.setColor(j++, 0xff000000 | colors.at(i).rgb()); - } - } - - return image; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h deleted file mode 100644 index 0755a34b4a8..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11_p.h +++ /dev/null @@ -1,131 +0,0 @@ -// 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 - -#pragma once - -#include <QBitmap> -#include <QPixmap> - -#include <qpa/qplatformpixmap.h> -#include "qxcbnativepainting.h" - -typedef unsigned long XID; -typedef XID Drawable; -typedef XID Picture; -typedef XID Pixmap; - -QT_BEGIN_NAMESPACE - -class QX11PaintEngine; -struct QXImageWrapper; - -class QX11PlatformPixmap : public QPlatformPixmap -{ -public: - QX11PlatformPixmap(PixelType pixelType); - ~QX11PlatformPixmap(); - - QPlatformPixmap *createCompatiblePlatformPixmap() const override; - void resize(int width, int height) override; - void fromImage(const QImage &img, Qt::ImageConversionFlags flags) override; - void copy(const QPlatformPixmap *data, const QRect &rect) override; - bool scroll(int dx, int dy, const QRect &rect) override; - int metric(QPaintDevice::PaintDeviceMetric metric) const override; - void fill(const QColor &fillColor) override; - QBitmap mask() const override; - void setMask(const QBitmap &mask) override; - bool hasAlphaChannel() const override; - QPixmap transformed(const QTransform &matrix, Qt::TransformationMode mode) const override; - QImage toImage() const override; - QImage toImage(const QRect &rect) const override; - QPaintEngine *paintEngine() const override; - qreal devicePixelRatio() const override; - void setDevicePixelRatio(qreal scaleFactor) override; - - inline Drawable handle() const { return hd; } - inline Picture x11PictureHandle() const { return picture; } - inline const QXcbX11Info *x11_info() const { return &xinfo; } - - Pixmap x11ConvertToDefaultDepth(); - static XID createBitmapFromImage(const QImage &image); - -#if QT_CONFIG(xrender) - void convertToARGB32(bool preserveContents = true); -#endif - - bool isBackingStore() const; - void setIsBackingStore(bool on); -private: - friend class QX11PaintEngine; - friend const QXcbX11Info &qt_x11Info(const QPixmap &pixmap); - friend void qt_x11SetScreen(QPixmap &pixmap, int screen); - - void release(); - QImage toImage(const QXImageWrapper &xi, const QRect &rect) const; - QBitmap mask_to_bitmap(int screen) const; - static Pixmap bitmap_to_mask(const QBitmap &, int screen); - void bitmapFromImage(const QImage &image); - bool canTakeQImageFromXImage(const QXImageWrapper &xi) const; - QImage takeQImageFromXImage(const QXImageWrapper &xi) const; - - Pixmap hd = 0; - - enum Flag { - NoFlags = 0x0, - Uninitialized = 0x1, - Readonly = 0x2, - InvertedWhenBoundToTexture = 0x4, - GlSurfaceCreatedWithAlpha = 0x8, - IsBackingStore = 0x10 - }; - uint flags; - - QXcbX11Info xinfo; - Pixmap x11_mask; - Picture picture; - Picture mask_picture; - Pixmap hd2; // sorted in the default display depth - //QPixmap::ShareMode share_mode; - qreal dpr; - - QX11PaintEngine *pengine; -}; - -inline QX11PlatformPixmap *qt_x11Pixmap(const QPixmap &pixmap) -{ - return (pixmap.handle() && pixmap.handle()->classId() == QPlatformPixmap::X11Class) - ? static_cast<QX11PlatformPixmap *>(pixmap.handle()) - : nullptr; -} - -inline Picture qt_x11PictureHandle(const QPixmap &pixmap) -{ - if (QX11PlatformPixmap *pm = qt_x11Pixmap(pixmap)) - return pm->x11PictureHandle(); - - return 0; -} - -inline Pixmap qt_x11PixmapHandle(const QPixmap &pixmap) -{ - if (QX11PlatformPixmap *pm = qt_x11Pixmap(pixmap)) - return pm->handle(); - - return 0; -} - -inline const QXcbX11Info &qt_x11Info(const QPixmap &pixmap) -{ - if (QX11PlatformPixmap *pm = qt_x11Pixmap(pixmap)) { - return pm->xinfo; - } else { - static QXcbX11Info nullX11Info; - return nullX11Info; - } -} - -int qt_x11SetDefaultScreen(int screen); -void qt_x11SetScreen(QPixmap &pixmap, int screen); - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h b/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h deleted file mode 100644 index e1e31722d76..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qpolygonclipper_p.h +++ /dev/null @@ -1,278 +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 -// Qt-Security score:significant reason:default - -#pragma once - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qrect.h> -#include <QtGui/private/qdatabuffer_p.h> - -QT_BEGIN_NAMESPACE - -/* based on sutherland-hodgman line-by-line clipping, as described in - Computer Graphics and Principles */ -template <typename InType, typename OutType, typename CastType> class QPolygonClipper -{ -public: - QPolygonClipper() : - buffer1(0), buffer2(0) - { - x1 = y1 = x2 = y2 = 0; - } - - ~QPolygonClipper() - { - } - - void setBoundingRect(const QRect bounds) - { - x1 = bounds.x(); - x2 = bounds.x() + bounds.width(); - y1 = bounds.y(); - y2 = bounds.y() + bounds.height(); - } - - QRect boundingRect() - { - return QRect(QPoint(x1, y1), QPoint(x2, y2)); - } - - inline OutType intersectLeft(const OutType &p1, const OutType &p2) - { - OutType t; - qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x); - t.x = x1; - t.y = static_cast<CastType>(p2.y + (x1 - p2.x) * dy); - return t; - } - - - inline OutType intersectRight(const OutType &p1, const OutType &p2) - { - OutType t; - qreal dy = (p1.y - p2.y) / qreal(p1.x - p2.x); - t.x = x2; - t.y = static_cast<CastType>(p2.y + (x2 - p2.x) * dy); - return t; - } - - - inline OutType intersectTop(const OutType &p1, const OutType &p2) - { - OutType t; - qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y); - t.x = static_cast<CastType>(p2.x + (y1 - p2.y) * dx); - t.y = y1; - return t; - } - - - inline OutType intersectBottom(const OutType &p1, const OutType &p2) - { - OutType t; - qreal dx = (p1.x - p2.x) / qreal(p1.y - p2.y); - t.x = static_cast<CastType>(p2.x + (y2 - p2.y) * dx); - t.y = y2; - return t; - } - - - void clipPolygon(const InType *inPoints, int inCount, OutType **outPoints, int *outCount, - bool closePolygon = true) - { - Q_ASSERT(outPoints); - Q_ASSERT(outCount); - - if (inCount < 2) { - *outCount = 0; - return; - } - - buffer1.reset(); - buffer2.reset(); - - QDataBuffer<OutType> *source = &buffer1; - QDataBuffer<OutType> *clipped = &buffer2; - - // Gather some info since we are iterating through the points anyway.. - bool doLeft = false, doRight = false, doTop = false, doBottom = false; - OutType ot; - for (int i=0; i<inCount; ++i) { - ot = inPoints[i]; - clipped->add(ot); - - if (ot.x < x1) - doLeft = true; - else if (ot.x > x2) - doRight = true; - if (ot.y < y1) - doTop = true; - else if (ot.y > y2) - doBottom = true; - } - - if (doLeft && clipped->size() > 1) { - QDataBuffer<OutType> *tmp = source; - source = clipped; - clipped = tmp; - clipped->reset(); - int lastPos, start; - if (closePolygon) { - lastPos = source->size() - 1; - start = 0; - } else { - lastPos = 0; - start = 1; - if (source->at(0).x >= x1) - clipped->add(source->at(0)); - } - for (int i=start; i<inCount; ++i) { - const OutType &cpt = source->at(i); - const OutType &ppt = source->at(lastPos); - - if (cpt.x >= x1) { - if (ppt.x >= x1) { - clipped->add(cpt); - } else { - clipped->add(intersectLeft(cpt, ppt)); - clipped->add(cpt); - } - } else if (ppt.x >= x1) { - clipped->add(intersectLeft(cpt, ppt)); - } - lastPos = i; - } - } - - if (doRight && clipped->size() > 1) { - QDataBuffer<OutType> *tmp = source; - source = clipped; - clipped = tmp; - clipped->reset(); - int lastPos, start; - if (closePolygon) { - lastPos = source->size() - 1; - start = 0; - } else { - lastPos = 0; - start = 1; - if (source->at(0).x <= x2) - clipped->add(source->at(0)); - } - for (int i=start; i<source->size(); ++i) { - const OutType &cpt = source->at(i); - const OutType &ppt = source->at(lastPos); - - if (cpt.x <= x2) { - if (ppt.x <= x2) { - clipped->add(cpt); - } else { - clipped->add(intersectRight(cpt, ppt)); - clipped->add(cpt); - } - } else if (ppt.x <= x2) { - clipped->add(intersectRight(cpt, ppt)); - } - - lastPos = i; - } - - } - - if (doTop && clipped->size() > 1) { - QDataBuffer<OutType> *tmp = source; - source = clipped; - clipped = tmp; - clipped->reset(); - int lastPos, start; - if (closePolygon) { - lastPos = source->size() - 1; - start = 0; - } else { - lastPos = 0; - start = 1; - if (source->at(0).y >= y1) - clipped->add(source->at(0)); - } - for (int i=start; i<source->size(); ++i) { - const OutType &cpt = source->at(i); - const OutType &ppt = source->at(lastPos); - - if (cpt.y >= y1) { - if (ppt.y >= y1) { - clipped->add(cpt); - } else { - clipped->add(intersectTop(cpt, ppt)); - clipped->add(cpt); - } - } else if (ppt.y >= y1) { - clipped->add(intersectTop(cpt, ppt)); - } - - lastPos = i; - } - } - - if (doBottom && clipped->size() > 1) { - QDataBuffer<OutType> *tmp = source; - source = clipped; - clipped = tmp; - clipped->reset(); - int lastPos, start; - if (closePolygon) { - lastPos = source->size() - 1; - start = 0; - } else { - lastPos = 0; - start = 1; - if (source->at(0).y <= y2) - clipped->add(source->at(0)); - } - for (int i=start; i<source->size(); ++i) { - const OutType &cpt = source->at(i); - const OutType &ppt = source->at(lastPos); - - if (cpt.y <= y2) { - if (ppt.y <= y2) { - clipped->add(cpt); - } else { - clipped->add(intersectBottom(cpt, ppt)); - clipped->add(cpt); - } - } else if (ppt.y <= y2) { - clipped->add(intersectBottom(cpt, ppt)); - } - lastPos = i; - } - } - - if (closePolygon && clipped->size() > 0) { - // close clipped polygon - if (clipped->at(0).x != clipped->at(clipped->size()-1).x || - clipped->at(0).y != clipped->at(clipped->size()-1).y) { - OutType ot = clipped->at(0); - clipped->add(ot); - } - } - *outCount = clipped->size(); - *outPoints = clipped->data(); - } - -private: - int x1, x2, y1, y2; - QDataBuffer<OutType> buffer1; - QDataBuffer<OutType> buffer2; -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h b/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h deleted file mode 100644 index 2986b8f1453..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qt_x11_p.h +++ /dev/null @@ -1,163 +0,0 @@ -// 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 - -#pragma once - -#define register /* C++17 deprecated register */ -#include <X11/Xlib.h> -#include <X11/Xatom.h> -#undef register - -#if QT_CONFIG(xrender) -# include "qtessellator_p.h" -# include <X11/extensions/Xrender.h> -#endif - -#if QT_CONFIG(fontconfig) -#include <fontconfig/fontconfig.h> -#endif - -#if defined(FT_LCD_FILTER_H) -#include FT_LCD_FILTER_H -#endif - -#if defined(FC_LCD_FILTER) - -#ifndef FC_LCD_FILTER_NONE -#define FC_LCD_FILTER_NONE FC_LCD_NONE -#endif - -#ifndef FC_LCD_FILTER_DEFAULT -#define FC_LCD_FILTER_DEFAULT FC_LCD_DEFAULT -#endif - -#ifndef FC_LCD_FILTER_LIGHT -#define FC_LCD_FILTER_LIGHT FC_LCD_LIGHT -#endif - -#ifndef FC_LCD_FILTER_LEGACY -#define FC_LCD_FILTER_LEGACY FC_LCD_LEGACY -#endif - -#endif - -QT_BEGIN_NAMESPACE - -// rename a couple of X defines to get rid of name clashes -// resolve the conflict between X11's FocusIn and QEvent::FocusIn -enum { - XFocusOut = FocusOut, - XFocusIn = FocusIn, - XKeyPress = KeyPress, - XKeyRelease = KeyRelease, - XNone = None, - XRevertToParent = RevertToParent, - XGrayScale = GrayScale, - XCursorShape = CursorShape, -}; -#undef FocusOut -#undef FocusIn -#undef KeyPress -#undef KeyRelease -#undef None -#undef RevertToParent -#undef GrayScale -#undef CursorShape - -#ifdef FontChange -#undef FontChange -#endif - -Q_DECLARE_TYPEINFO(XPoint, Q_PRIMITIVE_TYPE); -Q_DECLARE_TYPEINFO(XRectangle, Q_PRIMITIVE_TYPE); -Q_DECLARE_TYPEINFO(XChar2b, Q_PRIMITIVE_TYPE); -#if QT_CONFIG(xrender) -Q_DECLARE_TYPEINFO(XGlyphElt32, Q_PRIMITIVE_TYPE); -#endif - -struct QX11InfoData; - -enum DesktopEnvironment { - DE_UNKNOWN, - DE_KDE, - DE_GNOME, - DE_CDE, - DE_MEEGO_COMPOSITOR, - DE_4DWM -}; - -struct QXcbX11Data { - Display *display = nullptr; - - // true if Qt is compiled w/ RENDER support and RENDER is supported on the connected Display - bool use_xrender = false; - int xrender_major = 0; - int xrender_version = 0; - - QX11InfoData *screens = nullptr; - Visual **argbVisuals = nullptr; - Colormap *argbColormaps = nullptr; - int screenCount = 0; - int defaultScreen = 0; - - // options - int visual_class = 0; - int visual_id = 0; - int color_count = 0; - bool custom_cmap = false; - - // outside visual/colormap - Visual *visual = nullptr; - Colormap colormap = 0; - -#if QT_CONFIG(xrender) - enum { solid_fill_count = 16 }; - struct SolidFills { - XRenderColor color; - int screen; - Picture picture; - } solid_fills[solid_fill_count]; - enum { pattern_fill_count = 16 }; - struct PatternFills { - XRenderColor color; - XRenderColor bg_color; - int screen; - int style; - bool opaque; - Picture picture; - } pattern_fills[pattern_fill_count]; - Picture getSolidFill(int screen, const QColor &c); - XRenderColor preMultiply(const QColor &c); -#endif - - bool fc_antialias = true; - int fc_hint_style = 0; - - DesktopEnvironment desktopEnvironment = DE_GNOME; -}; - -extern QXcbX11Data *qt_x11Data; -#define X11 qt_x11Data - -struct QX11InfoData { - int screen; - int dpiX; - int dpiY; - int depth; - int cells; - Colormap colormap; - Visual *visual; - bool defaultColormap; - bool defaultVisual; - int subpixel = 0; -}; - -template <class T> -constexpr inline int lowest_bit(T v) noexcept -{ - int result = qCountTrailingZeroBits(v); - return ((result >> 3) == sizeof(T)) ? -1 : result; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp b/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp deleted file mode 100644 index dd83f8852b7..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qtessellator.cpp +++ /dev/null @@ -1,1466 +0,0 @@ -// 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 - -#include "qtessellator_p.h" - -#include <QRect> -#include <QList> -#include <QMap> -#include <QDebug> - -#include <qmath.h> -#include <limits.h> -#include <algorithm> - -QT_BEGIN_NAMESPACE - -//#define DEBUG -#ifdef DEBUG -#define QDEBUG qDebug -#else -#define QDEBUG if (1){} else qDebug -#endif - -static const bool emit_clever = true; -static const bool mark_clever = false; - -enum VertexFlags { - LineBeforeStarts = 0x1, - LineBeforeEnds = 0x2, - LineBeforeHorizontal = 0x4, - LineAfterStarts = 0x8, - LineAfterEnds = 0x10, - LineAfterHorizontal = 0x20 -}; - - - -class QTessellatorPrivate { -public: - struct Vertices; - - QTessellatorPrivate() {} - - QRectF collectAndSortVertices(const QPointF *points, int *maxActiveEdges); - void cancelCoincidingEdges(); - - void emitEdges(QTessellator *tessellator); - void processIntersections(); - void removeEdges(); - void addEdges(); - void addIntersections(); - - struct Vertex : public QTessellator::Vertex - { - int flags; - }; - - struct Intersection - { - Q27Dot5 y; - int edge; - bool operator <(const Intersection &other) const { - if (y != other.y) - return y < other.y; - return edge < other.edge; - } - }; - struct IntersectionLink - { - int next; - int prev; - }; - typedef QMap<Intersection, IntersectionLink> Intersections; - - struct Edge { - Edge(const Vertices &v, int _edge); - int edge; - const Vertex *v0; - const Vertex *v1; - Q27Dot5 y_left; - Q27Dot5 y_right; - signed int winding : 8; - bool mark; - bool free; - bool intersect_left; - bool intersect_right; - bool isLeftOf(const Edge &other, Q27Dot5 y) const; - Q27Dot5 positionAt(Q27Dot5 y) const; - bool intersect(const Edge &other, Q27Dot5 *y, bool *det_positive) const; - - }; - - class EdgeSorter - { - public: - EdgeSorter(int _y) : y(_y) {} - bool operator() (const Edge *e1, const Edge *e2); - int y; - }; - - class Scanline { - public: - Scanline(); - ~Scanline(); - - void init(int maxActiveEdges); - void done(); - - int findEdgePosition(Q27Dot5 x, Q27Dot5 y) const; - int findEdgePosition(const Edge &e) const; - int findEdge(int edge) const; - void clearMarks(); - - void swap(int p1, int p2) { - Edge *tmp = edges[p1]; - edges[p1] = edges[p2]; - edges[p2] = tmp; - } - void insert(int pos, const Edge &e); - void removeAt(int pos); - void markEdges(int pos1, int pos2); - - void prepareLine(); - void lineDone(); - - Edge **old; - int old_size; - - Edge **edges; - int size; - - private: - Edge *edge_table; - int first_unused; - int max_edges; - enum { default_alloc = 32 }; - }; - - struct Vertices { - enum { default_alloc = 128 }; - Vertices(); - ~Vertices(); - void init(int maxVertices); - void done(); - Vertex *storage; - Vertex **sorted; - - Vertex *operator[] (int i) { return storage + i; } - const Vertex *operator[] (int i) const { return storage + i; } - int position(const Vertex *v) const { - return v - storage; - } - Vertex *next(Vertex *v) { - ++v; - if (v == storage + nPoints) - v = storage; - return v; - } - const Vertex *next(const Vertex *v) const { - ++v; - if (v == storage + nPoints) - v = storage; - return v; - } - int nextPos(const Vertex *v) const { - ++v; - if (v == storage + nPoints) - return 0; - return v - storage; - } - Vertex *prev(Vertex *v) { - if (v == storage) - v = storage + nPoints; - --v; - return v; - } - const Vertex *prev(const Vertex *v) const { - if (v == storage) - v = storage + nPoints; - --v; - return v; - } - int prevPos(const Vertex *v) const { - if (v == storage) - v = storage + nPoints; - --v; - return v - storage; - } - int nPoints; - int allocated; - }; - Vertices vertices; - Intersections intersections; - Scanline scanline; - bool winding; - Q27Dot5 y; - int currentVertex; - -private: - void addIntersection(const Edge *e1, const Edge *e2); - bool edgeInChain(Intersection i, int edge); -}; - - -QTessellatorPrivate::Edge::Edge(const QTessellatorPrivate::Vertices &vertices, int edge) -{ - this->edge = edge; - intersect_left = intersect_right = true; - mark = false; - free = false; - - v0 = vertices[edge]; - v1 = vertices.next(v0); - - Q_ASSERT(v0->y != v1->y); - - if (v0->y > v1->y) { - qSwap(v0, v1); - winding = -1; - } else { - winding = 1; - } - y_left = y_right = v0->y; -} - -// This is basically the algorithm from graphics gems. The algorithm -// is cubic in the coordinates at one place. Since we use 64bit -// integers, this implies, that the allowed range for our coordinates -// is limited to 21 bits. With 5 bits behind the decimal, this -// implies that differences in coordaintes can range from 2*SHORT_MIN -// to 2*SHORT_MAX, giving us efficiently a coordinate system from -// SHORT_MIN to SHORT_MAX. -// - -// WARNING: It's absolutely critical that the intersect() and isLeftOf() methods use -// exactly the same algorithm to calculate yi. It's also important to be sure the algorithms -// are transitive (ie. the conditions below are true for all input data): -// -// a.intersect(b) == b.intersect(a) -// a.isLeftOf(b) != b.isLeftOf(a) -// -// This is tricky to get right, so be very careful when changing anything in here! - -static inline bool sameSign(qint64 a, qint64 b) { - return (((qint64) ((quint64) a ^ (quint64) b)) >= 0 ); -} - -bool QTessellatorPrivate::Edge::intersect(const Edge &other, Q27Dot5 *y, bool *det_positive) const -{ - qint64 a1 = v1->y - v0->y; - qint64 b1 = v0->x - v1->x; - - qint64 a2 = other.v1->y - other.v0->y; - qint64 b2 = other.v0->x - other.v1->x; - - qint64 det = a1 * b2 - a2 * b1; - if (det == 0) - return false; - - qint64 c1 = qint64(v1->x) * v0->y - qint64(v0->x) * v1->y; - - qint64 r3 = a1 * other.v0->x + b1 * other.v0->y + c1; - qint64 r4 = a1 * other.v1->x + b1 * other.v1->y + c1; - - // Check signs of r3 and r4. If both point 3 and point 4 lie on - // same side of line 1, the line segments do not intersect. - QDEBUG() << " " << r3 << r4; - if (r3 != 0 && r4 != 0 && sameSign( r3, r4 )) - return false; - - qint64 c2 = qint64(other.v1->x) * other.v0->y - qint64(other.v0->x) * other.v1->y; - - qint64 r1 = a2 * v0->x + b2 * v0->y + c2; - qint64 r2 = a2 * v1->x + b2 * v1->y + c2; - - // Check signs of r1 and r2. If both point 1 and point 2 lie - // on same side of second line segment, the line segments do not intersect. - QDEBUG() << " " << r1 << r2; - if (r1 != 0 && r2 != 0 && sameSign( r1, r2 )) - return false; - - // The det/2 is to get rounding instead of truncating. It - // is added or subtracted to the numerator, depending upon the - // sign of the numerator. - qint64 offset = det < 0 ? -det : det; - offset >>= 1; - - qint64 num = a2 * c1 - a1 * c2; - *y = ( num < 0 ? num - offset : num + offset ) / det; - - *det_positive = (det > 0); - - return true; -} - -#undef SAME_SIGNS - -bool QTessellatorPrivate::Edge::isLeftOf(const Edge &other, Q27Dot5 y) const -{ -// QDEBUG() << "isLeftOf" << edge << other.edge << y; - qint64 a1 = v1->y - v0->y; - qint64 b1 = v0->x - v1->x; - qint64 a2 = other.v1->y - other.v0->y; - qint64 b2 = other.v0->x - other.v1->x; - - qint64 c2 = qint64(other.v1->x) * other.v0->y - qint64(other.v0->x) * other.v1->y; - - qint64 det = a1 * b2 - a2 * b1; - if (det == 0) { - // lines are parallel. Only need to check side of one point - // fixed ordering for coincident edges - qint64 r1 = a2 * v0->x + b2 * v0->y + c2; -// QDEBUG() << "det = 0" << r1; - if (r1 == 0) - return edge < other.edge; - return (r1 < 0); - } - - // not parallel, need to find the y coordinate of the intersection point - qint64 c1 = qint64(v1->x) * v0->y - qint64(v0->x) * v1->y; - - qint64 offset = det < 0 ? -det : det; - offset >>= 1; - - qint64 num = a2 * c1 - a1 * c2; - qint64 yi = ( num < 0 ? num - offset : num + offset ) / det; -// QDEBUG() << " num=" << num << "offset=" << offset << "det=" << det; - - return ((yi > y) ^ (det < 0)); -} - -static inline bool compareVertex(const QTessellatorPrivate::Vertex *p1, - const QTessellatorPrivate::Vertex *p2) -{ - if (p1->y == p2->y) { - if (p1->x == p2->x) - return p1 < p2; - return p1->x < p2->x; - } - return p1->y < p2->y; -} - -Q27Dot5 QTessellatorPrivate::Edge::positionAt(Q27Dot5 y) const -{ - if (y == v0->y) - return v0->x; - else if (y == v1->y) - return v1->x; - - qint64 d = v1->x - v0->x; - return (v0->x + d*(y - v0->y)/(v1->y-v0->y)); -} - -bool QTessellatorPrivate::EdgeSorter::operator() (const Edge *e1, const Edge *e2) -{ - return e1->isLeftOf(*e2, y); -} - - -QTessellatorPrivate::Scanline::Scanline() -{ - edges = 0; - edge_table = 0; - old = 0; -} - -void QTessellatorPrivate::Scanline::init(int maxActiveEdges) -{ - maxActiveEdges *= 2; - if (!edges || maxActiveEdges > default_alloc) { - max_edges = maxActiveEdges; - int s = qMax(maxActiveEdges + 1, default_alloc + 1); - edges = q_check_ptr((Edge **)realloc(edges, s*sizeof(Edge *))); - edge_table = q_check_ptr((Edge *)realloc(edge_table, s*sizeof(Edge))); - old = q_check_ptr((Edge **)realloc(old, s*sizeof(Edge *))); - } - size = 0; - old_size = 0; - first_unused = 0; - for (int i = 0; i < maxActiveEdges; ++i) - edge_table[i].edge = i+1; - edge_table[maxActiveEdges].edge = -1; -} - -void QTessellatorPrivate::Scanline::done() -{ - if (max_edges > default_alloc) { - free(edges); - free(old); - free(edge_table); - edges = 0; - old = 0; - edge_table = 0; - } -} - -QTessellatorPrivate::Scanline::~Scanline() -{ - free(edges); - free(old); - free(edge_table); -} - -int QTessellatorPrivate::Scanline::findEdgePosition(Q27Dot5 x, Q27Dot5 y) const -{ - int min = 0; - int max = size - 1; - while (min < max) { - int pos = min + ((max - min + 1) >> 1); - Q27Dot5 ax = edges[pos]->positionAt(y); - if (ax > x) { - max = pos - 1; - } else { - min = pos; - } - } - return min; -} - -int QTessellatorPrivate::Scanline::findEdgePosition(const Edge &e) const -{ -// qDebug() << ">> findEdgePosition"; - int min = 0; - int max = size; - while (min < max) { - int pos = min + ((max - min) >> 1); -// qDebug() << " " << min << max << pos << edges[pos]->isLeftOf(e, e.y0); - if (edges[pos]->isLeftOf(e, e.v0->y)) { - min = pos + 1; - } else { - max = pos; - } - } -// qDebug() << "<< findEdgePosition got" << min; - return min; -} - -int QTessellatorPrivate::Scanline::findEdge(int edge) const -{ - for (int i = 0; i < size; ++i) { - int item_edge = edges[i]->edge; - if (item_edge == edge) - return i; - } - //Q_ASSERT(false); - return -1; -} - -void QTessellatorPrivate::Scanline::clearMarks() -{ - for (int i = 0; i < size; ++i) { - edges[i]->mark = false; - edges[i]->intersect_left = false; - edges[i]->intersect_right = false; - } -} - -void QTessellatorPrivate::Scanline::prepareLine() -{ - Edge **end = edges + size; - Edge **e = edges; - Edge **o = old; - while (e < end) { - *o = *e; - ++o; - ++e; - } - old_size = size; -} - -void QTessellatorPrivate::Scanline::lineDone() -{ - Edge **end = old + old_size; - Edge **e = old; - while (e < end) { - if ((*e)->free) { - (*e)->edge = first_unused; - first_unused = (*e - edge_table); - } - ++e; - } -} - -void QTessellatorPrivate::Scanline::insert(int pos, const Edge &e) -{ - Edge *edge = edge_table + first_unused; - first_unused = edge->edge; - Q_ASSERT(first_unused != -1); - *edge = e; - memmove(edges + pos + 1, edges + pos, (size - pos)*sizeof(Edge *)); - edges[pos] = edge; - ++size; -} - -void QTessellatorPrivate::Scanline::removeAt(int pos) -{ - Edge *e = edges[pos]; - e->free = true; - --size; - memmove(edges + pos, edges + pos + 1, (size - pos)*sizeof(Edge *)); -} - -void QTessellatorPrivate::Scanline::markEdges(int pos1, int pos2) -{ - if (pos2 < pos1) - return; - - for (int i = pos1; i <= pos2; ++i) - edges[i]->mark = true; -} - - -QTessellatorPrivate::Vertices::Vertices() -{ - storage = 0; - sorted = 0; - allocated = 0; - nPoints = 0; -} - -QTessellatorPrivate::Vertices::~Vertices() -{ - if (storage) { - free(storage); - free(sorted); - } -} - -void QTessellatorPrivate::Vertices::init(int maxVertices) -{ - if (!storage || maxVertices > allocated) { - int size = qMax((int)default_alloc, maxVertices); - storage = q_check_ptr((Vertex *)realloc(storage, size*sizeof(Vertex))); - sorted = q_check_ptr((Vertex **)realloc(sorted, size*sizeof(Vertex *))); - allocated = maxVertices; - } -} - -void QTessellatorPrivate::Vertices::done() -{ - if (allocated > default_alloc) { - free(storage); - free(sorted); - storage = 0; - sorted = 0; - allocated = 0; - } -} - - - -static inline void fillTrapezoid(Q27Dot5 y1, Q27Dot5 y2, int left, int right, - const QTessellatorPrivate::Vertices &vertices, - QTessellator::Trapezoid *trap) -{ - trap->top = y1; - trap->bottom = y2; - const QTessellatorPrivate::Vertex *v = vertices[left]; - trap->topLeft = v; - trap->bottomLeft = vertices.next(v); - if (trap->topLeft->y > trap->bottomLeft->y) - qSwap(trap->topLeft,trap->bottomLeft); - v = vertices[right]; - trap->topRight = v; - trap->bottomRight = vertices.next(v); - if (trap->topRight->y > trap->bottomRight->y) - qSwap(trap->topRight, trap->bottomRight); -} - -QRectF QTessellatorPrivate::collectAndSortVertices(const QPointF *points, int *maxActiveEdges) -{ - *maxActiveEdges = 0; - Vertex *v = vertices.storage; - Vertex **vv = vertices.sorted; - - qreal xmin(points[0].x()); - qreal xmax(points[0].x()); - qreal ymin(points[0].y()); - qreal ymax(points[0].y()); - - // collect vertex data - Q27Dot5 y_prev = FloatToQ27Dot5(points[vertices.nPoints-1].y()); - Q27Dot5 x_next = FloatToQ27Dot5(points[0].x()); - Q27Dot5 y_next = FloatToQ27Dot5(points[0].y()); - int j = 0; - int i = 0; - while (i < vertices.nPoints) { - Q27Dot5 y_curr = y_next; - - *vv = v; - - v->x = x_next; - v->y = y_next; - v->flags = 0; - - next_point: - - xmin = qMin(xmin, points[i+1].x()); - xmax = qMax(xmax, points[i+1].x()); - ymin = qMin(ymin, points[i+1].y()); - ymax = qMax(ymax, points[i+1].y()); - - y_next = FloatToQ27Dot5(points[i+1].y()); - x_next = FloatToQ27Dot5(points[i+1].x()); - - // skip vertices on top of each other - if (v->x == x_next && v->y == y_next) { - ++i; - if (i < vertices.nPoints) - goto next_point; - Vertex *v0 = vertices.storage; - v0->flags &= ~(LineBeforeStarts|LineBeforeEnds|LineBeforeHorizontal); - if (y_prev < y_curr) - v0->flags |= LineBeforeEnds; - else if (y_prev > y_curr) - v0->flags |= LineBeforeStarts; - else - v0->flags |= LineBeforeHorizontal; - if ((v0->flags & (LineBeforeStarts|LineAfterStarts)) - && !(v0->flags & (LineAfterEnds|LineBeforeEnds))) - *maxActiveEdges += 2; - break; - } - - if (y_prev < y_curr) - v->flags |= LineBeforeEnds; - else if (y_prev > y_curr) - v->flags |= LineBeforeStarts; - else - v->flags |= LineBeforeHorizontal; - - - if (y_curr < y_next) - v->flags |= LineAfterStarts; - else if (y_curr > y_next) - v->flags |= LineAfterEnds; - else - v->flags |= LineAfterHorizontal; - // ### could probably get better limit by looping over sorted list and counting down on ending edges - if ((v->flags & (LineBeforeStarts|LineAfterStarts)) - && !(v->flags & (LineAfterEnds|LineBeforeEnds))) - *maxActiveEdges += 2; - y_prev = y_curr; - ++v; - ++vv; - ++j; - ++i; - } - vertices.nPoints = j; - - QDEBUG() << "maxActiveEdges=" << *maxActiveEdges; - vv = vertices.sorted; - std::sort(vv, vv + vertices.nPoints, compareVertex); - - return QRectF(xmin, ymin, xmax-xmin, ymax-ymin); -} - -struct QCoincidingEdge { - QTessellatorPrivate::Vertex *start; - QTessellatorPrivate::Vertex *end; - bool used; - bool before; - - inline bool operator<(const QCoincidingEdge &e2) const - { - return end->y == e2.end->y ? end->x < e2.end->x : end->y < e2.end->y; - } -}; - -static void cancelEdges(QCoincidingEdge &e1, QCoincidingEdge &e2) -{ - if (e1.before) { - e1.start->flags &= ~(LineBeforeStarts|LineBeforeHorizontal); - e1.end->flags &= ~(LineAfterEnds|LineAfterHorizontal); - } else { - e1.start->flags &= ~(LineAfterStarts|LineAfterHorizontal); - e1.end->flags &= ~(LineBeforeEnds|LineBeforeHorizontal); - } - if (e2.before) { - e2.start->flags &= ~(LineBeforeStarts|LineBeforeHorizontal); - e2.end->flags &= ~(LineAfterEnds|LineAfterHorizontal); - } else { - e2.start->flags &= ~(LineAfterStarts|LineAfterHorizontal); - e2.end->flags &= ~(LineBeforeEnds|LineBeforeHorizontal); - } - e1.used = e2.used = true; -} - -void QTessellatorPrivate::cancelCoincidingEdges() -{ - Vertex **vv = vertices.sorted; - - QCoincidingEdge *tl = nullptr; - int tlSize = 0; - - for (int i = 0; i < vertices.nPoints - 1; ++i) { - Vertex *v = vv[i]; - int testListSize = 0; - while (i < vertices.nPoints - 1) { - Vertex *n = vv[i]; - if (v->x != n->x || v->y != n->y) - break; - - if (testListSize > tlSize - 2) { - tlSize = qMax(tlSize*2, 16); - tl = q_check_ptr((QCoincidingEdge *)realloc(tl, tlSize*sizeof(QCoincidingEdge))); - } - if (n->flags & (LineBeforeStarts|LineBeforeHorizontal)) { - tl[testListSize].start = n; - tl[testListSize].end = vertices.prev(n); - tl[testListSize].used = false; - tl[testListSize].before = true; - ++testListSize; - } - if (n->flags & (LineAfterStarts|LineAfterHorizontal)) { - tl[testListSize].start = n; - tl[testListSize].end = vertices.next(n); - tl[testListSize].used = false; - tl[testListSize].before = false; - ++testListSize; - } - ++i; - } - if (!testListSize) - continue; - - std::sort(tl, tl + testListSize); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_CLANG("-Wfor-loop-analysis") - for (int j = 0; j < testListSize; ++j) { - if (tl[j].used) - continue; - - for (int k = j + 1; k < testListSize; ++k) { - if (tl[j].end->x != tl[k].end->x - || tl[j].end->y != tl[k].end->y - || tl[k].used) - break; - - if (!winding || tl[j].before != tl[k].before) { - cancelEdges(tl[j], tl[k]); - break; - } - ++k; - } - ++j; - } -QT_WARNING_POP - } - free(tl); -} - - -void QTessellatorPrivate::emitEdges(QTessellator *tessellator) -{ - //QDEBUG() << "TRAPS:"; - if (!scanline.old_size) - return; - - // emit edges - if (winding) { - // winding fill rule - int w = 0; - - scanline.old[0]->y_left = y; - - for (int i = 0; i < scanline.old_size - 1; ++i) { - Edge *left = scanline.old[i]; - Edge *right = scanline.old[i+1]; - w += left->winding; -// qDebug() << "i=" << i << "edge->winding=" << left->winding << "winding=" << winding; - if (w == 0) { - left->y_right = y; - right->y_left = y; - } else if (!emit_clever || left->mark || right->mark) { - Q27Dot5 top = qMax(left->y_right, right->y_left); - if (top != y) { - QTessellator::Trapezoid trap; - fillTrapezoid(top, y, left->edge, right->edge, vertices, &trap); - tessellator->addTrap(trap); -// QDEBUG() << " top=" << Q27Dot5ToDouble(top) << "left=" << left->edge << "right=" << right->edge; - } - right->y_left = y; - left->y_right = y; - } - left->mark = false; - } - if (scanline.old[scanline.old_size - 1]->mark) { - scanline.old[scanline.old_size - 1]->y_right = y; - scanline.old[scanline.old_size - 1]->mark = false; - } - } else { - // odd-even fill rule - for (int i = 0; i < scanline.old_size; i += 2) { - Edge *left = scanline.old[i]; - Edge *right = scanline.old[i+1]; - if (!emit_clever || left->mark || right->mark) { - Q27Dot5 top = qMax(left->y_right, right->y_left); - if (top != y) { - QTessellator::Trapezoid trap; - fillTrapezoid(top, y, left->edge, right->edge, vertices, &trap); - tessellator->addTrap(trap); - } -// QDEBUG() << " top=" << Q27Dot5ToDouble(top) << "left=" << left->edge << "right=" << right->edge; - left->y_left = y; - left->y_right = y; - right->y_left = y; - right->y_right = y; - left->mark = right->mark = false; - } - } - } -} - - -void QTessellatorPrivate::processIntersections() -{ - QDEBUG() << "PROCESS INTERSECTIONS"; - // process intersections - while (!intersections.isEmpty()) { - Intersections::iterator it = intersections.begin(); - if (it.key().y != y) - break; - - // swap edges - QDEBUG() << " swapping intersecting edges "; - int min = scanline.size; - int max = 0; - Q27Dot5 xmin = INT_MAX; - Q27Dot5 xmax = INT_MIN; - int num = 0; - while (1) { - const Intersection i = it.key(); - int next = it->next; - - int edgePos = scanline.findEdge(i.edge); - if (edgePos >= 0) { - ++num; - min = qMin(edgePos, min); - max = qMax(edgePos, max); - Edge *edge = scanline.edges[edgePos]; - xmin = qMin(xmin, edge->positionAt(y)); - xmax = qMax(xmax, edge->positionAt(y)); - } - Intersection key; - key.y = y; - key.edge = next; - it = intersections.find(key); - intersections.remove(i); - if (it == intersections.end()) - break; - } - if (num < 2) - continue; - - Q_ASSERT(min != max); - QDEBUG() << "sorting between" << min << "and" << max << "xpos=" << xmin << xmax; - while (min > 0 && scanline.edges[min - 1]->positionAt(y) >= xmin) { - QDEBUG() << " adding edge on left"; - --min; - } - while (max < scanline.size - 1 && scanline.edges[max + 1]->positionAt(y) <= xmax) { - QDEBUG() << " adding edge on right"; - ++max; - } - - std::sort(scanline.edges + min, scanline.edges + max + 1, EdgeSorter(y)); -#ifdef DEBUG - for (int i = min; i <= max; ++i) - QDEBUG() << " " << scanline.edges[i]->edge << "at pos" << i; -#endif - for (int i = min; i <= max; ++i) { - Edge *edge = scanline.edges[i]; - edge->intersect_left = true; - edge->intersect_right = true; - edge->mark = true; - } - } -} - -void QTessellatorPrivate::removeEdges() -{ - int cv = currentVertex; - while (cv < vertices.nPoints) { - const Vertex *v = vertices.sorted[cv]; - if (v->y > y) - break; - if (v->flags & LineBeforeEnds) { - QDEBUG() << " removing edge" << vertices.prevPos(v); - int pos = scanline.findEdge(vertices.prevPos(v)); - if (pos == -1) - continue; - scanline.edges[pos]->mark = true; - if (pos > 0) - scanline.edges[pos - 1]->intersect_right = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->intersect_left = true; - scanline.removeAt(pos); - } - if (v->flags & LineAfterEnds) { - QDEBUG() << " removing edge" << vertices.position(v); - int pos = scanline.findEdge(vertices.position(v)); - if (pos == -1) - continue; - scanline.edges[pos]->mark = true; - if (pos > 0) - scanline.edges[pos - 1]->intersect_right = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->intersect_left = true; - scanline.removeAt(pos); - } - ++cv; - } -} - -void QTessellatorPrivate::addEdges() -{ - while (currentVertex < vertices.nPoints) { - const Vertex *v = vertices.sorted[currentVertex]; - if (v->y > y) - break; - if (v->flags & LineBeforeStarts) { - // add new edge - int start = vertices.prevPos(v); - Edge e(vertices, start); - int pos = scanline.findEdgePosition(e); - QDEBUG() << " adding edge" << start << "at position" << pos; - scanline.insert(pos, e); - if (!mark_clever || !(v->flags & LineAfterEnds)) { - if (pos > 0) - scanline.edges[pos - 1]->mark = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->mark = true; - } - } - if (v->flags & LineAfterStarts) { - Edge e(vertices, vertices.position(v)); - int pos = scanline.findEdgePosition(e); - QDEBUG() << " adding edge" << vertices.position(v) << "at position" << pos; - scanline.insert(pos, e); - if (!mark_clever || !(v->flags & LineBeforeEnds)) { - if (pos > 0) - scanline.edges[pos - 1]->mark = true; - if (pos < scanline.size - 1) - scanline.edges[pos + 1]->mark = true; - } - } - if (v->flags & LineAfterHorizontal) { - int pos1 = scanline.findEdgePosition(v->x, v->y); - const Vertex *next = vertices.next(v); - Q_ASSERT(v->y == next->y); - int pos2 = scanline.findEdgePosition(next->x, next->y); - if (pos2 < pos1) - qSwap(pos1, pos2); - if (pos1 > 0) - --pos1; - if (pos2 == scanline.size) - --pos2; - //QDEBUG() << "marking horizontal edge from " << pos1 << "to" << pos2; - scanline.markEdges(pos1, pos2); - } - ++currentVertex; - } -} - -#ifdef DEBUG -static void checkLinkChain(const QTessellatorPrivate::Intersections &intersections, - QTessellatorPrivate::Intersection i) -{ -// qDebug() << " Link chain: "; - int end = i.edge; - while (1) { - QTessellatorPrivate::IntersectionLink l = intersections.value(i); -// qDebug() << " " << i.edge << "next=" << l.next << "prev=" << l.prev; - if (l.next == end) - break; - Q_ASSERT(l.next != -1); - Q_ASSERT(l.prev != -1); - - QTessellatorPrivate::Intersection i2 = i; - i2.edge = l.next; - QTessellatorPrivate::IntersectionLink l2 = intersections.value(i2); - - Q_ASSERT(l2.next != -1); - Q_ASSERT(l2.prev != -1); - Q_ASSERT(l.next == i2.edge); - Q_ASSERT(l2.prev == i.edge); - i = i2; - } -} -#endif - -bool QTessellatorPrivate::edgeInChain(Intersection i, int edge) -{ - int end = i.edge; - while (1) { - if (i.edge == edge) - return true; - IntersectionLink l = intersections.value(i); - if (l.next == end) - break; - Q_ASSERT(l.next != -1); - Q_ASSERT(l.prev != -1); - - Intersection i2 = i; - i2.edge = l.next; - -#ifndef QT_NO_DEBUG - IntersectionLink l2 = intersections.value(i2); - Q_ASSERT(l2.next != -1); - Q_ASSERT(l2.prev != -1); - Q_ASSERT(l.next == i2.edge); - Q_ASSERT(l2.prev == i.edge); -#endif - i = i2; - } - return false; -} - - -void QTessellatorPrivate::addIntersection(const Edge *e1, const Edge *e2) -{ - const IntersectionLink emptyLink = {-1, -1}; - - int next = vertices.nextPos(vertices[e1->edge]); - if (e2->edge == next) - return; - int prev = vertices.prevPos(vertices[e1->edge]); - if (e2->edge == prev) - return; - - Q27Dot5 yi; - bool det_positive; - bool isect = e1->intersect(*e2, &yi, &det_positive); - QDEBUG("checking edges %d and %d", e1->edge, e2->edge); - if (!isect) { - QDEBUG() << " no intersection"; - return; - } - - // don't emit an intersection if it's at the start of a line segment or above us - if (yi <= y) { - if (!det_positive) - return; - QDEBUG() << " ----->>>>>> WRONG ORDER!"; - yi = y; - } - QDEBUG() << " between edges " << e1->edge << "and" << e2->edge << "at point (" - << Q27Dot5ToDouble(yi) << ')'; - - Intersection i1; - i1.y = yi; - i1.edge = e1->edge; - IntersectionLink link1 = intersections.value(i1, emptyLink); - Intersection i2; - i2.y = yi; - i2.edge = e2->edge; - IntersectionLink link2 = intersections.value(i2, emptyLink); - - // new pair of edges - if (link1.next == -1 && link2.next == -1) { - link1.next = link1.prev = i2.edge; - link2.next = link2.prev = i1.edge; - } else if (link1.next == i2.edge || link1.prev == i2.edge - || link2.next == i1.edge || link2.prev == i1.edge) { -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); - Q_ASSERT(edgeInChain(i1, i2.edge)); -#endif - return; - } else if (link1.next == -1 || link2.next == -1) { - if (link2.next == -1) { - qSwap(i1, i2); - qSwap(link1, link2); - } - Q_ASSERT(link1.next == -1); -#ifdef DEBUG - checkLinkChain(intersections, i2); -#endif - // only i2 in list - link1.next = i2.edge; - link1.prev = link2.prev; - link2.prev = i1.edge; - Intersection other; - other.y = yi; - other.edge = link1.prev; - IntersectionLink link = intersections.value(other, emptyLink); - Q_ASSERT(link.next == i2.edge); - Q_ASSERT(link.prev != -1); - link.next = i1.edge; - intersections.insert(other, link); - } else { - bool connected = edgeInChain(i1, i2.edge); - if (connected) - return; -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); -#endif - // both already in some list. Have to make sure they are connected - // this can be done by cutting open the ring(s) after the two eges and - // connecting them again - Intersection other1; - other1.y = yi; - other1.edge = link1.next; - IntersectionLink linko1 = intersections.value(other1, emptyLink); - Intersection other2; - other2.y = yi; - other2.edge = link2.next; - IntersectionLink linko2 = intersections.value(other2, emptyLink); - - linko1.prev = i2.edge; - link2.next = other1.edge; - - linko2.prev = i1.edge; - link1.next = other2.edge; - intersections.insert(other1, linko1); - intersections.insert(other2, linko2); - } - intersections.insert(i1, link1); - intersections.insert(i2, link2); -#ifdef DEBUG - checkLinkChain(intersections, i1); - checkLinkChain(intersections, i2); - Q_ASSERT(edgeInChain(i1, i2.edge)); -#endif - return; - -} - - -void QTessellatorPrivate::addIntersections() -{ - if (scanline.size) { - QDEBUG() << "INTERSECTIONS"; - // check marked edges for intersections -#ifdef DEBUG - for (int i = 0; i < scanline.size; ++i) { - Edge *e = scanline.edges[i]; - QDEBUG() << " " << i << e->edge << "isect=(" << e->intersect_left << e->intersect_right - << ')'; - } -#endif - - for (int i = 0; i < scanline.size - 1; ++i) { - Edge *e1 = scanline.edges[i]; - Edge *e2 = scanline.edges[i + 1]; - // check for intersection - if (e1->intersect_right || e2->intersect_left) - addIntersection(e1, e2); - } - } -#if 0 - if (intersections.constBegin().key().y == y) { - QDEBUG() << "----------------> intersection on same line"; - scanline.clearMarks(); - scanline.processIntersections(y, &intersections); - goto redo; - } -#endif -} - - -QTessellator::QTessellator() -{ - d = new QTessellatorPrivate; -} - -QTessellator::~QTessellator() -{ - delete d; -} - -void QTessellator::setWinding(bool w) -{ - d->winding = w; -} - - -QRectF QTessellator::tessellate(const QPointF *points, int nPoints) -{ - Q_ASSERT(points[0] == points[nPoints-1]); - --nPoints; - -#ifdef DEBUG - QDEBUG()<< "POINTS:"; - for (int i = 0; i < nPoints; ++i) { - QDEBUG() << points[i]; - } -#endif - - // collect edges and calculate bounds - d->vertices.nPoints = nPoints; - d->vertices.init(nPoints); - - int maxActiveEdges = 0; - QRectF br = d->collectAndSortVertices(points, &maxActiveEdges); - d->cancelCoincidingEdges(); - -#ifdef DEBUG - QDEBUG() << "nPoints = " << nPoints << "using " << d->vertices.nPoints; - QDEBUG()<< "VERTICES:"; - for (int i = 0; i < d->vertices.nPoints; ++i) { - QDEBUG() << " " << i << ": " - << "point=" << d->vertices.position(d->vertices.sorted[i]) - << "flags=" << d->vertices.sorted[i]->flags - << "pos=(" << Q27Dot5ToDouble(d->vertices.sorted[i]->x) << '/' - << Q27Dot5ToDouble(d->vertices.sorted[i]->y) << ')'; - } -#endif - - d->scanline.init(maxActiveEdges); - d->y = INT_MIN/256; - d->currentVertex = 0; - - while (d->currentVertex < d->vertices.nPoints) { - d->scanline.clearMarks(); - - d->y = d->vertices.sorted[d->currentVertex]->y; - if (!d->intersections.isEmpty()) - d->y = qMin(d->y, d->intersections.constBegin().key().y); - - QDEBUG()<< "===== SCANLINE: y =" << Q27Dot5ToDouble(d->y) << " ====="; - - d->scanline.prepareLine(); - d->processIntersections(); - d->removeEdges(); - d->addEdges(); - d->addIntersections(); - d->emitEdges(this); - d->scanline.lineDone(); - -#ifdef DEBUG - QDEBUG()<< "===== edges:"; - for (int i = 0; i < d->scanline.size; ++i) { - QDEBUG() << " " << d->scanline.edges[i]->edge - << "p0= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v0->x) - << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v0->y) - << ") p1= (" << Q27Dot5ToDouble(d->scanline.edges[i]->v1->x) - << '/' << Q27Dot5ToDouble(d->scanline.edges[i]->v1->y) << ')' - << "x=" << Q27Dot5ToDouble(d->scanline.edges[i]->positionAt(d->y)) - << "isLeftOfNext=" - << ((i < d->scanline.size - 1) - ? d->scanline.edges[i]->isLeftOf(*d->scanline.edges[i+1], d->y) - : true); - } -#endif -} - - d->scanline.done(); - d->intersections.clear(); - return br; -} - -// tessellates the given convex polygon -void QTessellator::tessellateConvex(const QPointF *points, int nPoints) -{ - Q_ASSERT(points[0] == points[nPoints-1]); - --nPoints; - - d->vertices.nPoints = nPoints; - d->vertices.init(nPoints); - - for (int i = 0; i < nPoints; ++i) { - d->vertices[i]->x = FloatToQ27Dot5(points[i].x()); - d->vertices[i]->y = FloatToQ27Dot5(points[i].y()); - } - - int left = 0, right = 0; - - int top = 0; - for (int i = 1; i < nPoints; ++i) { - if (d->vertices[i]->y < d->vertices[top]->y) - top = i; - } - - left = (top + nPoints - 1) % nPoints; - right = (top + 1) % nPoints; - - while (d->vertices[left]->x == d->vertices[top]->x && d->vertices[left]->y == d->vertices[top]->y && left != right) - left = (left + nPoints - 1) % nPoints; - - while (d->vertices[right]->x == d->vertices[top]->x && d->vertices[right]->y == d->vertices[top]->y && left != right) - right = (right + 1) % nPoints; - - if (left == right) - return; - - int dir = 1; - - Vertex dLeft = { d->vertices[top]->x - d->vertices[left]->x, - d->vertices[top]->y - d->vertices[left]->y }; - - Vertex dRight = { d->vertices[right]->x - d->vertices[top]->x, - d->vertices[right]->y - d->vertices[top]->y }; - - Q27Dot5 cross = dLeft.x * dRight.y - dLeft.y * dRight.x; - - // flip direction if polygon is clockwise - if (cross < 0 || (cross == 0 && dLeft.x > 0)) { - qSwap(left, right); - dir = -1; - } - - Vertex *lastLeft = d->vertices[top]; - Vertex *lastRight = d->vertices[top]; - - QTessellator::Trapezoid trap; - - while (lastLeft->y == d->vertices[left]->y && left != right) { - lastLeft = d->vertices[left]; - left = (left + nPoints - dir) % nPoints; - } - - while (lastRight->y == d->vertices[right]->y && left != right) { - lastRight = d->vertices[right]; - right = (right + nPoints + dir) % nPoints; - } - - while (true) { - trap.top = qMax(lastRight->y, lastLeft->y); - trap.bottom = qMin(d->vertices[left]->y, d->vertices[right]->y); - trap.topLeft = lastLeft; - trap.topRight = lastRight; - trap.bottomLeft = d->vertices[left]; - trap.bottomRight = d->vertices[right]; - - if (trap.bottom > trap.top) - addTrap(trap); - - if (left == right) - break; - - if (d->vertices[right]->y < d->vertices[left]->y) { - do { - lastRight = d->vertices[right]; - right = (right + nPoints + dir) % nPoints; - } - while (lastRight->y == d->vertices[right]->y && left != right); - } else { - do { - lastLeft = d->vertices[left]; - left = (left + nPoints - dir) % nPoints; - } - while (lastLeft->y == d->vertices[left]->y && left != right); - } - } -} - -// tessellates the stroke of the line from a_ to b_ with the given width and a flat cap -void QTessellator::tessellateRect(const QPointF &a_, const QPointF &b_, qreal width) -{ - Vertex a = { FloatToQ27Dot5(a_.x()), FloatToQ27Dot5(a_.y()) }; - Vertex b = { FloatToQ27Dot5(b_.x()), FloatToQ27Dot5(b_.y()) }; - - QPointF pa = a_, pb = b_; - - if (a.y > b.y) { - qSwap(a, b); - qSwap(pa, pb); - } - - Vertex delta = { b.x - a.x, b.y - a.y }; - - if (delta.x == 0 && delta.y == 0) - return; - - qreal hw = 0.5 * width; - - if (delta.x == 0) { - Q27Dot5 halfWidth = FloatToQ27Dot5(hw); - - if (halfWidth == 0) - return; - - Vertex topLeft = { a.x - halfWidth, a.y }; - Vertex topRight = { a.x + halfWidth, a.y }; - Vertex bottomLeft = { a.x - halfWidth, b.y }; - Vertex bottomRight = { a.x + halfWidth, b.y }; - - QTessellator::Trapezoid trap = { topLeft.y, bottomLeft.y, &topLeft, &bottomLeft, &topRight, &bottomRight }; - addTrap(trap); - } else if (delta.y == 0) { - Q27Dot5 halfWidth = FloatToQ27Dot5(hw); - - if (halfWidth == 0) - return; - - if (a.x > b.x) - qSwap(a.x, b.x); - - Vertex topLeft = { a.x, a.y - halfWidth }; - Vertex topRight = { b.x, a.y - halfWidth }; - Vertex bottomLeft = { a.x, a.y + halfWidth }; - Vertex bottomRight = { b.x, a.y + halfWidth }; - - QTessellator::Trapezoid trap = { topLeft.y, bottomLeft.y, &topLeft, &bottomLeft, &topRight, &bottomRight }; - addTrap(trap); - } else { - QPointF perp(pb.y() - pa.y(), pa.x() - pb.x()); - qreal length = qSqrt(perp.x() * perp.x() + perp.y() * perp.y()); - - if (qFuzzyIsNull(length)) - return; - - // need the half of the width - perp *= hw / length; - - QPointF pta = pa + perp; - QPointF ptb = pa - perp; - QPointF ptc = pb - perp; - QPointF ptd = pb + perp; - - Vertex ta = { FloatToQ27Dot5(pta.x()), FloatToQ27Dot5(pta.y()) }; - Vertex tb = { FloatToQ27Dot5(ptb.x()), FloatToQ27Dot5(ptb.y()) }; - Vertex tc = { FloatToQ27Dot5(ptc.x()), FloatToQ27Dot5(ptc.y()) }; - Vertex td = { FloatToQ27Dot5(ptd.x()), FloatToQ27Dot5(ptd.y()) }; - - if (ta.y < tb.y) { - if (tb.y < td.y) { - QTessellator::Trapezoid top = { ta.y, tb.y, &ta, &tb, &ta, &td }; - QTessellator::Trapezoid bottom = { td.y, tc.y, &tb, &tc, &td, &tc }; - addTrap(top); - addTrap(bottom); - - QTessellator::Trapezoid middle = { tb.y, td.y, &tb, &tc, &ta, &td }; - addTrap(middle); - } else { - QTessellator::Trapezoid top = { ta.y, td.y, &ta, &tb, &ta, &td }; - QTessellator::Trapezoid bottom = { tb.y, tc.y, &tb, &tc, &td, &tc }; - addTrap(top); - addTrap(bottom); - - if (tb.y != td.y) { - QTessellator::Trapezoid middle = { td.y, tb.y, &ta, &tb, &td, &tc }; - addTrap(middle); - } - } - } else { - if (ta.y < tc.y) { - QTessellator::Trapezoid top = { tb.y, ta.y, &tb, &tc, &tb, &ta }; - QTessellator::Trapezoid bottom = { tc.y, td.y, &tc, &td, &ta, &td }; - addTrap(top); - addTrap(bottom); - - QTessellator::Trapezoid middle = { ta.y, tc.y, &tb, &tc, &ta, &td }; - addTrap(middle); - } else { - QTessellator::Trapezoid top = { tb.y, tc.y, &tb, &tc, &tb, &ta }; - QTessellator::Trapezoid bottom = { ta.y, td.y, &tc, &td, &ta, &td }; - addTrap(top); - addTrap(bottom); - - if (ta.y != tc.y) { - QTessellator::Trapezoid middle = { tc.y, ta.y, &tc, &td, &tb, &ta }; - addTrap(middle); - } - } - } - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h b/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h deleted file mode 100644 index ba1d3a971a3..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qtessellator_p.h +++ /dev/null @@ -1,51 +0,0 @@ -// 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 - -#pragma once - -#include <QPoint> -#include <QRect> - -QT_BEGIN_NAMESPACE - -class QTessellatorPrivate; - -typedef int Q27Dot5; -#define Q27Dot5ToDouble(i) ((i)/32.) -#define FloatToQ27Dot5(i) (int)((i) * 32) -#define IntToQ27Dot5(i) ((i) << 5) -#define Q27Dot5ToXFixed(i) ((i) << 11) -#define Q27Dot5Factor 32 - -class QTessellator { -public: - QTessellator(); - virtual ~QTessellator(); - - QRectF tessellate(const QPointF *points, int nPoints); - void tessellateConvex(const QPointF *points, int nPoints); - void tessellateRect(const QPointF &a, const QPointF &b, qreal width); - - void setWinding(bool w); - - struct Vertex { - Q27Dot5 x; - Q27Dot5 y; - }; - struct Trapezoid { - Q27Dot5 top; - Q27Dot5 bottom; - const Vertex *topLeft; - const Vertex *bottomLeft; - const Vertex *topRight; - const Vertex *bottomRight; - }; - virtual void addTrap(const Trapezoid &trap) = 0; - -private: - friend class QTessellatorPrivate; - QTessellatorPrivate *d; -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp deleted file mode 100644 index 23155ef2e62..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.cpp +++ /dev/null @@ -1,288 +0,0 @@ -// 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 - -#include <QtCore/qrandom.h> - -#include "qxcbconnection.h" -#include "qcolormap_x11_p.h" -#include "qxcbnativepainting.h" -#include "qt_x11_p.h" - -QT_BEGIN_NAMESPACE - -QXcbX11Data *qt_x11Data = nullptr; - -void qt_xcb_native_x11_info_init(QXcbConnection *conn) -{ - qt_x11Data = new QXcbX11Data; - X11->display = static_cast<Display *>(conn->xlib_display()); - X11->defaultScreen = DefaultScreen(X11->display); - X11->screenCount = ScreenCount(X11->display); - - X11->screens = new QX11InfoData[X11->screenCount]; - X11->argbVisuals = new Visual *[X11->screenCount]; - X11->argbColormaps = new Colormap[X11->screenCount]; - - for (int s = 0; s < X11->screenCount; s++) { - QX11InfoData *screen = X11->screens + s; - //screen->ref = 1; // ensures it doesn't get deleted - screen->screen = s; - - int widthMM = DisplayWidthMM(X11->display, s); - if (widthMM != 0) { - screen->dpiX = (DisplayWidth(X11->display, s) * 254 + widthMM * 5) / (widthMM * 10); - } else { - screen->dpiX = 72; - } - - int heightMM = DisplayHeightMM(X11->display, s); - if (heightMM != 0) { - screen->dpiY = (DisplayHeight(X11->display, s) * 254 + heightMM * 5) / (heightMM * 10); - } else { - screen->dpiY = 72; - } - - X11->argbVisuals[s] = 0; - X11->argbColormaps[s] = 0; - } - - X11->use_xrender = conn->hasXRender() && !qEnvironmentVariableIsSet("QT_XCB_NATIVE_PAINTING_NO_XRENDER"); - -#if QT_CONFIG(xrender) - memset(X11->solid_fills, 0, sizeof(X11->solid_fills)); - for (int i = 0; i < X11->solid_fill_count; ++i) - X11->solid_fills[i].screen = -1; - memset(X11->pattern_fills, 0, sizeof(X11->pattern_fills)); - for (int i = 0; i < X11->pattern_fill_count; ++i) - X11->pattern_fills[i].screen = -1; -#endif - - QXcbColormap::initialize(); - -#if QT_CONFIG(xrender) - if (X11->use_xrender) { - // XRender is supported, let's see if we have a PictFormat for the - // default visual - XRenderPictFormat *format = - XRenderFindVisualFormat(X11->display, - (Visual *) QXcbX11Info::appVisual(X11->defaultScreen)); - - if (!format) { - X11->use_xrender = false; - } - } -#endif // QT_CONFIG(xrender) -} - -QList<XRectangle> qt_region_to_xrectangles(const QRegion &r) -{ - const int numRects = r.rectCount(); - const auto input = r.begin(); - QList<XRectangle> output(numRects); - for (int i = 0; i < numRects; ++i) { - const QRect &in = input[i]; - XRectangle &out = output[i]; - out.x = qMax(SHRT_MIN, in.x()); - out.y = qMax(SHRT_MIN, in.y()); - out.width = qMin((int)USHRT_MAX, in.width()); - out.height = qMin((int)USHRT_MAX, in.height()); - } - return output; -} - -class QXcbX11InfoData : public QSharedData, public QX11InfoData -{}; - -QXcbX11Info::QXcbX11Info() - : d(nullptr) -{} - -QXcbX11Info::~QXcbX11Info() -{} - -QXcbX11Info::QXcbX11Info(const QXcbX11Info &other) - : d(other.d) -{} - -QXcbX11Info &QXcbX11Info::operator=(const QXcbX11Info &other) -{ - d = other.d; - return *this; -} - -QXcbX11Info QXcbX11Info::fromScreen(int screen) -{ - QXcbX11InfoData *xd = new QXcbX11InfoData; - xd->screen = screen; - xd->depth = QXcbX11Info::appDepth(screen); - xd->cells = QXcbX11Info::appCells(screen); - xd->colormap = QXcbX11Info::appColormap(screen); - xd->defaultColormap = QXcbX11Info::appDefaultColormap(screen); - xd->visual = (Visual *)QXcbX11Info::appVisual(screen); - xd->defaultVisual = QXcbX11Info::appDefaultVisual(screen); - - QXcbX11Info info; - info.d = xd; - return info; -} - -void QXcbX11Info::setDepth(int depth) -{ - if (!d) - *this = fromScreen(appScreen()); - - d->depth = depth; -} - -Display *QXcbX11Info::display() -{ - return X11 ? X11->display : 0; -} - -int QXcbX11Info::screen() const -{ - return d ? d->screen : QXcbX11Info::appScreen(); -} - -int QXcbX11Info::depth() const -{ - return d ? d->depth : QXcbX11Info::appDepth(); -} - -Colormap QXcbX11Info::colormap() const -{ - return d ? d->colormap : QXcbX11Info::appColormap(); -} - -void *QXcbX11Info::visual() const -{ - return d ? d->visual : QXcbX11Info::appVisual(); -} - -void QXcbX11Info::setVisual(void *visual) -{ - if (!d) - *this = fromScreen(appScreen()); - - d->visual = (Visual *) visual; -} - -int QXcbX11Info::appScreen() -{ - return X11 ? X11->defaultScreen : 0; -} - -int QXcbX11Info::appDepth(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].depth : 32; -} - -int QXcbX11Info::appCells(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].cells : 0; -} - -Colormap QXcbX11Info::appColormap(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].colormap : 0; -} - -void *QXcbX11Info::appVisual(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].visual : 0; -} - -Window QXcbX11Info::appRootWindow(int screen) -{ - return X11 ? RootWindow(X11->display, screen == -1 ? X11->defaultScreen : screen) : 0; -} - -bool QXcbX11Info::appDefaultColormap(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultColormap : true; -} - -bool QXcbX11Info::appDefaultVisual(int screen) -{ - return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultVisual : true; -} - -int QXcbX11Info::appDpiX(int screen) -{ - if (!X11) - return 75; - if (screen < 0) - screen = X11->defaultScreen; - if (screen > X11->screenCount) - return 0; - return X11->screens[screen].dpiX; -} - -int QXcbX11Info::appDpiY(int screen) -{ - if (!X11) - return 75; - if (screen < 0) - screen = X11->defaultScreen; - if (screen > X11->screenCount) - return 0; - return X11->screens[screen].dpiY; -} - -#if QT_CONFIG(xrender) -Picture QXcbX11Data::getSolidFill(int screen, const QColor &c) -{ - if (!X11->use_xrender) - return XNone; - - XRenderColor color = preMultiply(c); - for (int i = 0; i < X11->solid_fill_count; ++i) { - if (X11->solid_fills[i].screen == screen - && X11->solid_fills[i].color.alpha == color.alpha - && X11->solid_fills[i].color.red == color.red - && X11->solid_fills[i].color.green == color.green - && X11->solid_fills[i].color.blue == color.blue) - return X11->solid_fills[i].picture; - } - // none found, replace one - int i = QRandomGenerator::global()->generate() % 16; - - if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) { - XRenderFreePicture (X11->display, X11->solid_fills[i].picture); - X11->solid_fills[i].picture = 0; - } - - if (!X11->solid_fills[i].picture) { - Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 1, 1, 32); - XRenderPictureAttributes attrs; - attrs.repeat = True; - X11->solid_fills[i].picture = XRenderCreatePicture (X11->display, pixmap, - XRenderFindStandardFormat(X11->display, PictStandardARGB32), - CPRepeat, &attrs); - XFreePixmap (X11->display, pixmap); - } - - X11->solid_fills[i].color = color; - X11->solid_fills[i].screen = screen; - XRenderFillRectangle (X11->display, PictOpSrc, X11->solid_fills[i].picture, &color, 0, 0, 1, 1); - return X11->solid_fills[i].picture; -} - -XRenderColor QXcbX11Data::preMultiply(const QColor &c) -{ - XRenderColor color; - const uint A = c.alpha(), - R = c.red(), - G = c.green(), - B = c.blue(); - color.alpha = (A | A << 8); - color.red = (R | R << 8) * color.alpha / 0x10000; - color.green = (G | G << 8) * color.alpha / 0x10000; - color.blue = (B | B << 8) * color.alpha / 0x10000; - return color; -} -#endif // QT_CONFIG(xrender) - - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h b/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h deleted file mode 100644 index dac9b101c43..00000000000 --- a/src/plugins/platforms/xcb/nativepainting/qxcbnativepainting.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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 - -#pragma once - -#include <QSharedDataPointer> -#include "qt_x11_p.h" - -typedef struct _FcPattern FcPattern; -typedef unsigned long XID; -typedef XID Colormap; -typedef XID Window; -typedef struct _XDisplay Display; - -QT_BEGIN_NAMESPACE - -class QXcbConnection; -class QPixmap; - -void qt_xcb_native_x11_info_init(QXcbConnection *conn); -QList<XRectangle> qt_region_to_xrectangles(const QRegion &r); - -class QXcbX11InfoData; -class QXcbX11Info -{ -public: - QXcbX11Info(); - ~QXcbX11Info(); - QXcbX11Info(const QXcbX11Info &other); - QXcbX11Info &operator=(const QXcbX11Info &other); - - static QXcbX11Info fromScreen(int screen); - static Display *display(); - - int depth() const; - void setDepth(int depth); - - int screen() const; - Colormap colormap() const; - - void *visual() const; - void setVisual(void *visual); - - static int appScreen(); - static int appDepth(int screen = -1); - static int appCells(int screen = -1); - static Colormap appColormap(int screen = -1); - static void *appVisual(int screen = -1); - static Window appRootWindow(int screen = -1); - static bool appDefaultColormap(int screen = -1); - static bool appDefaultVisual(int screen = -1); - static int appDpiX(int screen = -1); - static int appDpiY(int screen = -1); - -private: - QSharedDataPointer<QXcbX11InfoData> d; - - friend class QX11PaintEngine; - friend class QX11PlatformPixmap; - friend void qt_x11SetScreen(QPixmap &pixmap, int screen); -}; - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp index 5b78c2c08ab..4c978152975 100644 --- a/src/plugins/platforms/xcb/qxcbimage.cpp +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -80,12 +80,6 @@ bool qt_xcb_imageFormatForVisual(QXcbConnection *connection, uint8_t depth, cons *imageFormat = QImage::Format_Grayscale8; return true; } -#if QT_CONFIG(xcb_native_painting) - if (QXcbIntegration::instance() && QXcbIntegration::instance()->nativePaintingEnabled()) { - *imageFormat = QImage::Format_Indexed8; - return true; - } -#endif return false; } diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index c5c1fb1e638..d3a31dd35c7 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -37,11 +37,6 @@ #include <X11/Xlib.h> #undef register #endif -#if QT_CONFIG(xcb_native_painting) -#include "qxcbnativepainting.h" -#include "qpixmap_x11_p.h" -#include "qbackingstore_x11_p.h" -#endif #include <qpa/qplatforminputcontextfactory_p.h> #include <private/qgenericunixtheme_p.h> @@ -180,13 +175,6 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char m_services->setConnection(m_connection); m_fontDatabase.reset(new QGenericUnixFontDatabase()); - -#if QT_CONFIG(xcb_native_painting) - if (nativePaintingEnabled()) { - qCDebug(lcQpaXcb, "QXCB USING NATIVE PAINTING"); - qt_xcb_native_x11_info_init(connection()); - } -#endif } QXcbIntegration::~QXcbIntegration() @@ -198,11 +186,6 @@ QXcbIntegration::~QXcbIntegration() QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { -#if QT_CONFIG(xcb_native_painting) - if (nativePaintingEnabled()) - return new QX11PlatformPixmap(type); -#endif - return QPlatformIntegration::createPlatformPixmap(type); } @@ -281,10 +264,6 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window); if (isTrayIconWindow) { backingStore = new QXcbSystemTrayBackingStore(window); -#if QT_CONFIG(xcb_native_painting) - } else if (nativePaintingEnabled()) { - backingStore = new QXcbNativeBackingStore(window); -#endif } else { backingStore = new QXcbBackingStore(window); } @@ -576,16 +555,6 @@ void QXcbIntegration::beep() const xcb_flush(connection); } -bool QXcbIntegration::nativePaintingEnabled() const -{ -#if QT_CONFIG(xcb_native_painting) - static bool enabled = qEnvironmentVariableIsSet("QT_XCB_NATIVE_PAINTING"); - return enabled; -#else - return false; -#endif -} - #if QT_CONFIG(vulkan) QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const { diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 10cc67af55f..041908e4552 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -94,8 +94,6 @@ public: void beep() const override; - bool nativePaintingEnabled() const; - #if QT_CONFIG(vulkan) QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; #endif diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 2944c02fd79..c8cd7c26f61 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -109,6 +109,7 @@ inline ControlState calcControlState(const QStyleOption *option) #define More u"\uE712"_s #define Help u"\uE897"_s +#define Clear u"\uE894"_s template <typename R, typename P, typename B> static inline void drawRoundedRect(QPainter *p, R &&rect, P &&pen, B &&brush) @@ -1720,9 +1721,10 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op } case CE_ItemViewItem: { if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); - QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget); - QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget); + const auto p = proxy(); + QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); + QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget); + QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget); // draw the background proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget); @@ -1823,16 +1825,17 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op d->viewItemDrawText(painter, vopt, textRect); // paint a vertical marker for QListView - if (vopt->state & State_Selected) { + if (vopt->state & State_Selected && !highContrastTheme) { if (const QListView *lv = qobject_cast<const QListView *>(widget); - lv && lv->viewMode() != QListView::IconMode && !highContrastTheme) { - painter->setPen(vopt->palette.accent().color()); - const auto xPos = isRtl ? rect.right() - 1 : rect.left(); - const QLineF lines[2] = { - QLineF(xPos, rect.y() + 2, xPos, rect.y() + rect.height() - 2), - QLineF(xPos + 1, rect.y() + 2, xPos + 1, rect.y() + rect.height() - 2), - }; - painter->drawLines(lines, 2); + lv && lv->viewMode() != QListView::IconMode) { + const auto col = vopt->palette.accent().color(); + painter->setBrush(col); + painter->setPen(col); + const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f; + const auto yOfs = rect.height() / 4.; + QRectF r(QPointF(xPos, rect.y() + yOfs), + QPointF(xPos + 1, rect.y() + rect.height() - yOfs)); + painter->drawRoundedRect(r, 1, 1); } } } @@ -1872,7 +1875,7 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_RadioButtonIndicator: case QStyle::SE_CheckBoxIndicator: ret = QWindowsVistaStyle::subElementRect(element, option, widget); - ret.moveLeft(contentItemHMargin); + ret.moveLeft(ret.left() + contentItemHMargin); break; case QStyle::SE_ComboBoxFocusRect: case QStyle::SE_CheckBoxFocusRect: @@ -1883,22 +1886,29 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_LineEditContents: ret = option->rect.adjusted(4,0,-4,0); break; - case QStyle::SE_ItemViewItemText: - if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - const int decorationOffset = item->features.testFlag(QStyleOptionViewItem::HasDecoration) ? item->decorationSize.width() : 0; - const int checkboxOffset = item->features.testFlag(QStyleOptionViewItem::HasCheckIndicator) ? 16 : 0; - if (widget && qobject_cast<QComboBoxPrivateContainer *>(widget->parentWidget())) { - if (option->direction == Qt::LeftToRight) - ret = option->rect.adjusted(decorationOffset + checkboxOffset + 5, 0, -5, 0); - else - ret = option->rect.adjusted(5, 0, decorationOffset - checkboxOffset - 5, 0); + case SE_ItemViewItemCheckIndicator: + case SE_ItemViewItemDecoration: + case SE_ItemViewItemText: { + ret = QWindowsVistaStyle::subElementRect(element, option, widget); + if (!ret.isValid() || highContrastTheme) + return ret; + + if (const QListView *lv = qobject_cast<const QListView *>(widget); + lv && lv->viewMode() != QListView::IconMode) { + const int xOfs = contentHMargin; + const bool isRtl = option->direction == Qt::RightToLeft; + if (isRtl) { + ret.moveRight(ret.right() - xOfs); + if (ret.left() < option->rect.left()) + ret.setLeft(option->rect.left()); } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); + ret.moveLeft(ret.left() + xOfs); + if (ret.right() > option->rect.right()) + ret.setRight(option->rect.right()); } - } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); } break; + } #if QT_CONFIG(progressbar) case SE_ProgressBarGroove: case SE_ProgressBarContents: @@ -2091,6 +2101,19 @@ QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOption } break; } +#if QT_CONFIG(groupbox) + case CC_GroupBox: { + ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); + switch (subControl) { + case SC_GroupBoxCheckBox: + ret.moveTop(1); + break; + default: + break; + } + break; + } +#endif // QT_CONFIG(groupbox) default: ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); } @@ -2234,6 +2257,25 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o contentSize.rwidth() += 2 * contentHMargin - oldMargin; break; } + case CT_ItemViewItem: { + if (const auto *viewItemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { + if (const QListView *lv = qobject_cast<const QListView *>(widget); + lv && lv->viewMode() != QListView::IconMode) { + QStyleOptionViewItem vOpt(*viewItemOpt); + // viewItemSize only takes PM_FocusFrameHMargin into account but no additional + // margin, therefore adjust it here for a correct width during layouting when + // WrapText is enabled + vOpt.rect.setRight(vOpt.rect.right() - contentHMargin); + contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget); + contentSize.rwidth() += contentHMargin; + contentSize.rheight() += 2 * contentHMargin; + + } else { + contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); + } + } + break; + } default: contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); break; @@ -2544,6 +2586,7 @@ void QWindows11Style::polish(QPalette& result) d->m_titleBarCloseIcon = QIcon(); d->m_titleBarNormalIcon = QIcon(); d->m_toolbarExtensionButton = QIcon(); + d->m_lineEditClearButton = QIcon(); } QPixmap QWindows11Style::standardPixmap(StandardPixmap standardPixmap, @@ -2568,10 +2611,17 @@ QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon, { auto *d = const_cast<QWindows11StylePrivate*>(d_func()); switch (standardIcon) { + case SP_LineEditClearButton: { + if (d->m_lineEditClearButton.isNull()) { + auto e = new WinFontIconEngine(Clear.at(0), d->assetFont); + d->m_lineEditClearButton = QIcon(e); + } + return d->m_lineEditClearButton; + } case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: { if (d->m_toolbarExtensionButton.isNull()) { - auto e = new WinFontIconEngine(More.at(0), d->assetFont); + auto e = new WinFontIconEngine(More, d->assetFont); e->setScale(1.0); d->m_toolbarExtensionButton = QIcon(e); } diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h index 736caae956c..a51a93ddd9b 100644 --- a/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -123,6 +123,7 @@ class QWindows11StylePrivate : public QWindowsVistaStylePrivate { protected: QIcon m_toolbarExtensionButton; + QIcon m_lineEditClearButton; }; QT_END_NAMESPACE diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index 22ca18b10bf..fa0d0260f3c 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -4959,8 +4959,7 @@ QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon, return QWindowsStyle::standardIcon(standardIcon, option, widget); } - -WinFontIconEngine::WinFontIconEngine(const QChar &glyph, const QFont &font) +WinFontIconEngine::WinFontIconEngine(const QString &glyph, const QFont &font) : QFontIconEngine({}, font) , m_font(font) , m_glyph(glyph) diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h index cf982ceb133..23b34547faa 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h @@ -184,7 +184,7 @@ private: class WinFontIconEngine : public QFontIconEngine { public: - WinFontIconEngine(const QChar &glyph, const QFont &font); + WinFontIconEngine(const QString &glyph, const QFont &font); QString key() const override; QIconEngine *clone() const override; @@ -194,7 +194,7 @@ public: protected: QFont m_font; - QChar m_glyph; + QString m_glyph; double m_scale = 0.7; }; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 784e69d2486..a98f5da2389 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -410,7 +410,7 @@ public: static QMetaMethod findMethod(const QObject *obj, const char *signature); private: - bool invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const; + void invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const; void invokeTestOnData(int index) const; QMetaMethod m_initTestCaseMethod; // might not exist, check isValid(). @@ -1315,11 +1315,8 @@ static void printUnknownDataTagError(QLatin1StringView name, QLatin1StringView t Call slot_data(), init(), slot(), cleanup(), init(), slot(), cleanup(), ... If data is set then it is the only test that is performed - - If the function was successfully called, true is returned, otherwise - false. */ -bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const +void TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const { QBenchmarkTestMethodData benchmarkData; QBenchmarkTestMethodData::current = &benchmarkData; @@ -1422,8 +1419,6 @@ bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<Wat QTestResult::finishedCurrentTestFunction(); QTestResult::setSkipCurrentTest(false); QTestResult::setBlacklistCurrentTest(false); - - return true; } void *fetchData(QTestData *data, const char *tagName, int typeId) @@ -1743,10 +1738,8 @@ void TestMethods::invokeTests(QObject *testObject) const const char *data = nullptr; if (i < QTest::testTags.size() && !QTest::testTags.at(i).isEmpty()) data = qstrdup(QTest::testTags.at(i).toLatin1().constData()); - const bool ok = invokeTest(i, QLatin1StringView(data), watchDog); + invokeTest(i, QLatin1StringView(data), watchDog); delete [] data; - if (!ok) - break; } } diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp index fc969e17380..265c523eae0 100644 --- a/src/widgets/accessible/itemviews.cpp +++ b/src/widgets/accessible/itemviews.cpp @@ -60,7 +60,7 @@ int QAccessibleTable::logicalIndex(const QModelIndex &index) const } QAccessibleTable::QAccessibleTable(QWidget *w) - : QAccessibleObject(w) + : QAccessibleWidgetV2(w) { Q_ASSERT(view()); @@ -677,7 +677,7 @@ void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t) return static_cast<QAccessibleSelectionInterface*>(this); if (t == QAccessible::TableInterface) return static_cast<QAccessibleTableInterface*>(this); - return nullptr; + return QAccessibleWidgetV2::interface_cast(t); } void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event) diff --git a/src/widgets/accessible/itemviews_p.h b/src/widgets/accessible/itemviews_p.h index 9b30f36ced3..79f9a7f2f05 100644 --- a/src/widgets/accessible/itemviews_p.h +++ b/src/widgets/accessible/itemviews_p.h @@ -31,7 +31,9 @@ QT_BEGIN_NAMESPACE class QAccessibleTableCell; class QAccessibleTableHeaderCell; -class QAccessibleTable :public QAccessibleTableInterface, public QAccessibleSelectionInterface, public QAccessibleObject +class QAccessibleTable : public QAccessibleTableInterface, + public QAccessibleSelectionInterface, + public QAccessibleWidgetV2 { public: explicit QAccessibleTable(QWidget *w); diff --git a/src/widgets/accessible/rangecontrols.cpp b/src/widgets/accessible/rangecontrols.cpp index c0de5357c9a..1f7b20833dd 100644 --- a/src/widgets/accessible/rangecontrols.cpp +++ b/src/widgets/accessible/rangecontrols.cpp @@ -65,6 +65,16 @@ QAccessibleInterface *QAccessibleAbstractSpinBox::lineEditIface() const #endif } +QAccessible::State QAccessibleAbstractSpinBox::state() const +{ + QAccessible::State state = QAccessibleWidgetV2::state(); + if (abstractSpinBox()->isReadOnly()) + state.readOnly = true; + else + state.editable = true; + return state; +} + QString QAccessibleAbstractSpinBox::text(QAccessible::Text t) const { if (t == QAccessible::Value) diff --git a/src/widgets/accessible/rangecontrols_p.h b/src/widgets/accessible/rangecontrols_p.h index dd5a6a4531c..5a023d2f00b 100644 --- a/src/widgets/accessible/rangecontrols_p.h +++ b/src/widgets/accessible/rangecontrols_p.h @@ -42,6 +42,7 @@ public: explicit QAccessibleAbstractSpinBox(QWidget *w); virtual ~QAccessibleAbstractSpinBox(); + QAccessible::State state() const override; QString text(QAccessible::Text t) const override; void *interface_cast(QAccessible::InterfaceType t) override; diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 25d742039c5..f8125204045 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -585,18 +585,21 @@ signals: protected: QSize sizeHint() const override; void paintEvent(QPaintEvent*) override; + void keyPressEvent(QKeyEvent *event) override; void mouseMoveEvent(QMouseEvent *) override; void mousePressEvent(QMouseEvent *) override; void resizeEvent(QResizeEvent *) override; private: - int hue; - int sat; + QPoint m_pos; - QPoint colPt(); - int huePt(const QPoint &pt); - int satPt(const QPoint &pt); - void setCol(const QPoint &pt); + QPixmap createColorsPixmap(); + QPoint colPt(int hue, int sat); + int huePt(const QPoint &pt, const QSize &widgetSize); + int huePt(const QPoint &pt) { return huePt(pt, size()); } + int satPt(const QPoint &pt, const QSize &widgetSize); + int satPt(const QPoint &pt) { return satPt(pt, size()); } + void setCol(const QPoint &pt, bool notify = true); QPixmap pix; bool crossVisible; @@ -625,6 +628,7 @@ signals: protected: void paintEvent(QPaintEvent*) override; + void keyPressEvent(QKeyEvent *event) override; void mouseMoveEvent(QMouseEvent *) override; void mousePressEvent(QMouseEvent *) override; @@ -660,6 +664,7 @@ QColorLuminancePicker::QColorLuminancePicker(QWidget* parent) hue = 100; val = 100; sat = 100; pix = nullptr; // setAttribute(WA_NoErase, true); + setFocusPolicy(Qt::StrongFocus); } QColorLuminancePicker::~QColorLuminancePicker() @@ -667,6 +672,21 @@ QColorLuminancePicker::~QColorLuminancePicker() delete pix; } +void QColorLuminancePicker::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Down: + setVal(std::clamp(val - 1, 0, 255)); + break; + case Qt::Key_Up: + setVal(std::clamp(val + 1, 0, 255)); + break; + default: + QWidget::keyPressEvent(event); + break; + } +} + void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m) { if (m->buttons() == Qt::NoButton) { @@ -737,38 +757,53 @@ void QColorLuminancePicker::setCol(int h, int s , int v) repaint(); } -QPoint QColorPicker::colPt() +QPoint QColorPicker::colPt(int hue, int sat) { QRect r = contentsRect(); return QPoint((360 - hue) * (r.width() - 1) / 360, (255 - sat) * (r.height() - 1) / 255); } -int QColorPicker::huePt(const QPoint &pt) +int QColorPicker::huePt(const QPoint &pt, const QSize &widgetSize) { - QRect r = contentsRect(); - return 360 - pt.x() * 360 / (r.width() - 1); + QRect r = QRect(QPoint(0, 0), widgetSize) - contentsMargins(); + return std::clamp(360 - pt.x() * 360 / (r.width() - 1), 0, 359); } -int QColorPicker::satPt(const QPoint &pt) +int QColorPicker::satPt(const QPoint &pt, const QSize &widgetSize) { - QRect r = contentsRect(); - return 255 - pt.y() * 255 / (r.height() - 1); + QRect r = QRect(QPoint(0, 0), widgetSize) - contentsMargins(); + return std::clamp(255 - pt.y() * 255 / (r.height() - 1), 0, 255); } -void QColorPicker::setCol(const QPoint &pt) +void QColorPicker::setCol(const QPoint &pt, bool notify) { - setCol(huePt(pt), satPt(pt)); + if (pt == m_pos) + return; + + QRect r(m_pos, QSize(20, 20)); + m_pos.setX(std::clamp(pt.x(), 0, pix.width() - 1)); + m_pos.setY(std::clamp(pt.y(), 0, pix.height() - 1)); + r = r.united(QRect(m_pos, QSize(20, 20))); + r.translate(contentsRect().x() - 9, contentsRect().y() - 9); + // update(r); + repaint(r); + + if (notify) + emit newCol(huePt(m_pos), satPt(m_pos)); } QColorPicker::QColorPicker(QWidget* parent) : QFrame(parent) , crossVisible(true) { - hue = 0; sat = 0; - setCol(150, 255); - setAttribute(Qt::WA_NoSystemBackground); + setFocusPolicy(Qt::StrongFocus); setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) ); + adjustSize(); + + pix = createColorsPixmap(); + + setCol(150, 255); } QColorPicker::~QColorPicker() @@ -792,15 +827,31 @@ void QColorPicker::setCol(int h, int s) { int nhue = qMin(qMax(0,h), 359); int nsat = qMin(qMax(0,s), 255); - if (nhue == hue && nsat == sat) + if (nhue == huePt(m_pos) && nsat == satPt(m_pos)) return; - QRect r(colPt(), QSize(20,20)); - hue = nhue; sat = nsat; - r = r.united(QRect(colPt(), QSize(20,20))); - r.translate(contentsRect().x()-9, contentsRect().y()-9); - // update(r); - repaint(r); + setCol(colPt(nhue, nsat), false); +} + +void QColorPicker::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Down: + setCol(m_pos + QPoint(0, 1)); + break; + case Qt::Key_Left: + setCol(m_pos + QPoint(-1, 0)); + break; + case Qt::Key_Right: + setCol(m_pos + QPoint(1, 0)); + break; + case Qt::Key_Up: + setCol(m_pos + QPoint(0, -1)); + break; + default: + QFrame::keyPressEvent(event); + break; + } } void QColorPicker::mouseMoveEvent(QMouseEvent *m) @@ -811,14 +862,12 @@ void QColorPicker::mouseMoveEvent(QMouseEvent *m) return; } setCol(p); - emit newCol(hue, sat); } void QColorPicker::mousePressEvent(QMouseEvent *m) { QPoint p = m->position().toPoint() - contentsRect().topLeft(); setCol(p); - emit newCol(hue, sat); } void QColorPicker::paintEvent(QPaintEvent* ) @@ -830,7 +879,7 @@ void QColorPicker::paintEvent(QPaintEvent* ) p.drawPixmap(r.topLeft(), pix); if (crossVisible) { - QPoint pt = colPt() + r.topLeft(); + QPoint pt = m_pos + r.topLeft(); p.setPen(Qt::black); p.fillRect(pt.x()-9, pt.y(), 20, 2, Qt::black); p.fillRect(pt.x(), pt.y()-9, 2, 20, Qt::black); @@ -841,6 +890,21 @@ void QColorPicker::resizeEvent(QResizeEvent *ev) { QFrame::resizeEvent(ev); + pix = createColorsPixmap(); + + const QSize &oldSize = ev->oldSize(); + if (!oldSize.isValid()) + return; + + // calculate hue/saturation based on previous widget size + // and update position accordingly + const int hue = huePt(m_pos, oldSize); + const int sat = satPt(m_pos, oldSize); + setCol(hue, sat); +} + +QPixmap QColorPicker::createColorsPixmap() +{ int w = width() - frameWidth() * 2; int h = height() - frameWidth() * 2; QImage img(w, h, QImage::Format_RGB32); @@ -858,10 +922,9 @@ void QColorPicker::resizeEvent(QResizeEvent *ev) ++x; } } - pix = QPixmap::fromImage(img); + return QPixmap::fromImage(img); } - class QColSpinBox : public QSpinBox { public: diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp index 870b0c40faf..c4f8af1a639 100644 --- a/src/widgets/dialogs/qfontdialog.cpp +++ b/src/widgets/dialogs/qfontdialog.cpp @@ -172,7 +172,7 @@ void QFontDialogPrivate::init() sizeAccel = new QLabel(q); #ifndef QT_NO_SHORTCUT - sizeAccel->setBuddy(sizeEdit); + sizeAccel->setBuddy(sizeList); #endif sizeAccel->setIndent(2); diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index 00f9766af29..5ba92714f6c 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -345,6 +345,17 @@ void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) c } /*! + \property QLayout::contentsMargins + \since 4.6 + \brief the margins used around the layout + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa setContentsMargins(), getContentsMargins() +*/ + +/*! \since 4.6 Returns the margins used around the layout. |
