KRect and KRectF proposal
Vlad Zahorodnii
vlad.zahorodnii at kde.org
Tue Apr 7 20:56:19 BST 2026
Hi,
On 4/6/26 11:31 PM, Thiago Macieira wrote:
> On Friday, 27 March 2026 11:03:01 Pacific Daylight Time Vlad Zahorodnii wrote:
>> - `Rect::right()` and `Rect::bottom()` represent the true right and
>> bottom edges, respectively. In other words, `x() + width()` and `y() +
>> height()`;
> In other words, it's like containers: one-past-the-end. For a 1920x1080
> rectangle with the origin at 0,0, this would show right = 1920 and bottom =
> 1080, and yet the last pixel is actually (1919,1079). That's the semantic
> problem of QRect.
>
> Except you're doing:
>> - `RectF::contains()` does not consider the right and bottom edges
>> inside the rectangle. Current `QRectF::contains()` can lead to issues
>> with input handling;
> This is the big difference: the right and bottom edges (assuming positive) are
> not part of the surface. You have two edges that are inclusive and two that
> are exclusive.
That's correct. Effectively, when dealing with GUI, we expect that the
right and bottom edges are exclusive. We want the right edge to be `x +
width` but we don't want it to be inside the rectangle. You can view it
as a semi-open interval, i.e. [left, right) and [top, bottom). It makes
things such as hit tests produce less unexpected results.
> Speaking of negative, what happens if you have negative height and width?
> Which edge is exclusive?
Such rectangles will be considered invalid. So `::contains()` will
return false. You'll need to use either `::normalized()` or `::span()`
to get a proper rectangle. That's another (intentional) change that I
forgot to mention in the original message.
>> - `RectF::toRect()` rounds the coordinates of top, left, right, and
>> bottom edges;
> Away from each other, towards each other, or towards a particular direction?
> In other words, how do the height() and width() get rounded?
The final coordinates will be as follows:
- left = std::round(rect.x())
- right = std::round(rect.x() + rect.width())
- top = std::round(rect.y())
- bottom = std::round(rect.y() + rect.height())
or
- x = std::round(rect.x())
- y = std::round(rect.y())
- width = std::round(rect.x() + rect.width()) - std::round(rect.x())
- height = std::round(rect.y() + rect.height()) - std::round(rect.y())
The main reasoning behind this is HiDPI or fractional scaling to be
specific. We need a predictable rounding algorithm, which doesn't tend
to introduce gaps, and that's universal for both apps and compositors.
Although note that the rectangles are stored as (left, top, right,
bottom) tuples rather than (x, y, width, height) tuples, so it's just
four std::round() calls. The reasoning behind it is that the LTRB format
is nicer for contains(), intersects(), Region, etc.
> Suppose a rectangle of 1x1+0.5+0.5: do you round to 1x1+0+0 or 0x0+0+0?
1x1+1+1
>> Our long term hope is that Qt developers would see what KDE does with
>> `KRect` and `KRectF` and consider either fixing `QRect` and `QRectF` or
>> incorporating them as is to Qt. Right now, if we go with our list of
>> issues, we will likely be turned around with the reason that `QRect` and
>> `QRectF` have been working like this since the beginning and there is a
>> lot of software that can be broken, which is a really fair argument!
>> Still, it won't make the issues go away...
> The problem is legacy code, which is why it hasn't been fixed in 20 years that
> the pitfalls have been known. Therefore, not going to happen any time in the
> near future.
>
> What may happen is adding a new class that has the right semantics and hope
> that over time it replaces the old. This class could be added at any time,
> which is when transition could start. And if it is in QtCore, then Qt classes
> in other modules could begin using it. If it's in a KF6 library, Qt classes
> can't.
>
>> I would like to propose adding a new library, e.g. kprimitivetypes, that
>> would host `KRect` and `KRectF`. There is a slight challenge with KF
>> though. It will be nice if KConfig and maybe other tier 1 libraries are
>> able use `KRect(F)`. In order to achieve that, the new library will need
>> to live either outside of KF or perhaps there could be tier 0 in KF?
> Bring this discussion to the Qt dev mailing list so we can discuss having it
> in QtCore.
Okay, will do.
Regards,
Vlad
More information about the Kde-frameworks-devel
mailing list