core: Add OutputTransform::map(QRect,Size) overloads

These can be useful in case a QRect needs to be mapped. One could
convert the QRect into a QRectF and then back to QRect, but given that
these conversion helpers are present in rendering hot paths, it would
be great to be more efficient and also potentially loosing precision
because of floating point arithmetic.
This commit is contained in:
Vlad Zahorodnii 2023-12-20 10:58:26 +02:00
parent 98a1b5098a
commit a9b01a68b8
3 changed files with 125 additions and 0 deletions

View file

@ -20,8 +20,12 @@ public:
private Q_SLOTS:
void mapSizeF_data();
void mapSizeF();
void mapSize_data();
void mapSize();
void mapRectF_data();
void mapRectF();
void mapRect_data();
void mapRect();
void inverted_data();
void inverted();
void combine_data();
@ -59,6 +63,31 @@ void TestOutputTransform::mapSizeF()
QCOMPARE(OutputTransform(kind).map(source), target);
}
void TestOutputTransform::mapSize_data()
{
QTest::addColumn<OutputTransform::Kind>("kind");
QTest::addColumn<QSize>("source");
QTest::addColumn<QSize>("target");
QTest::addRow("rotate-0") << OutputTransform::Normal << QSize(10, 20) << QSize(10, 20);
QTest::addRow("rotate-90") << OutputTransform::Rotated90 << QSize(10, 20) << QSize(20, 10);
QTest::addRow("rotate-180") << OutputTransform::Rotated180 << QSize(10, 20) << QSize(10, 20);
QTest::addRow("rotate-270") << OutputTransform::Rotated270 << QSize(10, 20) << QSize(20, 10);
QTest::addRow("flip-0") << OutputTransform::Flipped << QSize(10, 20) << QSize(10, 20);
QTest::addRow("flip-90") << OutputTransform::Flipped90 << QSize(10, 20) << QSize(20, 10);
QTest::addRow("flip-180") << OutputTransform::Flipped180 << QSize(10, 20) << QSize(10, 20);
QTest::addRow("flip-270") << OutputTransform::Flipped270 << QSize(10, 20) << QSize(20, 10);
}
void TestOutputTransform::mapSize()
{
QFETCH(OutputTransform::Kind, kind);
QFETCH(QSize, source);
QFETCH(QSize, target);
QCOMPARE(OutputTransform(kind).map(source), target);
}
void TestOutputTransform::mapRectF_data()
{
QTest::addColumn<OutputTransform::Kind>("kind");
@ -84,6 +113,31 @@ void TestOutputTransform::mapRectF()
QCOMPARE(OutputTransform(kind).map(source, QSizeF(100, 200)), target);
}
void TestOutputTransform::mapRect_data()
{
QTest::addColumn<OutputTransform::Kind>("kind");
QTest::addColumn<QRect>("source");
QTest::addColumn<QRect>("target");
QTest::addRow("rotate-0") << OutputTransform::Normal << QRect(10, 20, 30, 40) << QRect(10, 20, 30, 40);
QTest::addRow("rotate-90") << OutputTransform::Rotated90 << QRect(10, 20, 30, 40) << QRect(140, 10, 40, 30);
QTest::addRow("rotate-180") << OutputTransform::Rotated180 << QRect(10, 20, 30, 40) << QRect(60, 140, 30, 40);
QTest::addRow("rotate-270") << OutputTransform::Rotated270 << QRect(10, 20, 30, 40) << QRect(20, 60, 40, 30);
QTest::addRow("flip-0") << OutputTransform::Flipped << QRect(10, 20, 30, 40) << QRect(60, 20, 30, 40);
QTest::addRow("flip-90") << OutputTransform::Flipped90 << QRect(10, 20, 30, 40) << QRect(20, 10, 40, 30);
QTest::addRow("flip-180") << OutputTransform::Flipped180 << QRect(10, 20, 30, 40) << QRect(10, 140, 30, 40);
QTest::addRow("flip-270") << OutputTransform::Flipped270 << QRect(10, 20, 30, 40) << QRect(140, 60, 40, 30);
}
void TestOutputTransform::mapRect()
{
QFETCH(OutputTransform::Kind, kind);
QFETCH(QRect, source);
QFETCH(QRect, target);
QCOMPARE(OutputTransform(kind).map(source, QSize(100, 200)), target);
}
void TestOutputTransform::inverted_data()
{
QTest::addColumn<OutputTransform::Kind>("kind");

View file

@ -143,6 +143,62 @@ QRectF OutputTransform::map(const QRectF &rect, const QSizeF &bounds) const
return dest;
}
QRect OutputTransform::map(const QRect &rect, const QSize &bounds) const
{
QRect dest;
switch (m_kind) {
case Kind::Normal:
case Kind::Rotated180:
case Kind::Flipped:
case Kind::Flipped180:
dest.setWidth(rect.width());
dest.setHeight(rect.height());
break;
default:
dest.setWidth(rect.height());
dest.setHeight(rect.width());
break;
}
switch (m_kind) {
case Kind::Normal:
dest.moveLeft(rect.x());
dest.moveTop(rect.y());
break;
case Kind::Rotated90:
dest.moveLeft(bounds.height() - (rect.y() + rect.height()));
dest.moveTop(rect.x());
break;
case Kind::Rotated180:
dest.moveLeft(bounds.width() - (rect.x() + rect.width()));
dest.moveTop(bounds.height() - (rect.y() + rect.height()));
break;
case Kind::Rotated270:
dest.moveLeft(rect.y());
dest.moveTop(bounds.width() - (rect.x() + rect.width()));
break;
case Kind::Flipped:
dest.moveLeft(bounds.width() - (rect.x() + rect.width()));
dest.moveTop(rect.y());
break;
case Kind::Flipped90:
dest.moveLeft(rect.y());
dest.moveTop(rect.x());
break;
case Kind::Flipped180:
dest.moveLeft(rect.x());
dest.moveTop(bounds.height() - (rect.y() + rect.height()));
break;
case Kind::Flipped270:
dest.moveLeft(bounds.height() - (rect.y() + rect.height()));
dest.moveTop(bounds.width() - (rect.x() + rect.width()));
break;
}
return dest;
}
QSizeF OutputTransform::map(const QSizeF &size) const
{
switch (m_kind) {
@ -156,6 +212,19 @@ QSizeF OutputTransform::map(const QSizeF &size) const
}
}
QSize OutputTransform::map(const QSize &size) const
{
switch (m_kind) {
case Kind::Normal:
case Kind::Rotated180:
case Kind::Flipped:
case Kind::Flipped180:
return size;
default:
return size.transposed();
}
}
OutputTransform OutputTransform::combine(OutputTransform other) const
{
const int flip = (m_kind ^ other.m_kind) & 0x4;

View file

@ -71,11 +71,13 @@ public:
* Applies the output transform to the given @a size.
*/
QSizeF map(const QSizeF &size) const;
QSize map(const QSize &size) const;
/**
* Applies the output transform to the given @a rect within a buffer with dimensions @a bounds.
*/
QRectF map(const QRectF &rect, const QSizeF &bounds) const;
QRect map(const QRect &rect, const QSize &bounds) const;
/**
* Returns an output transform that is equivalent to applying this transform and @a other