Bug 428973 - Border one pixel off when drawing 'QStyle::PE_Frame' primitive using Breeze style
Summary: Border one pixel off when drawing 'QStyle::PE_Frame' primitive using Breeze s...
Status: RESOLVED FIXED
Alias: None
Product: Breeze
Classification: Plasma
Component: QStyle (show other bugs)
Version: 5.17.5
Platform: Other Linux
: NOR normal
Target Milestone: ---
Assignee: Unassigned bugs mailing-list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-11-11 13:07 UTC by Michael Weghorn
Modified: 2020-11-11 20:57 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In: 5.21


Attachments
Small sample program (673 bytes, text/x-c++src)
2020-11-11 13:07 UTC, Michael Weghorn
Details
Image created by running the sample program (253 bytes, image/png)
2020-11-11 13:08 UTC, Michael Weghorn
Details
Screenshot of enlarged image (where exact pixels can be seen more easily) (1.71 KB, image/png)
2020-11-11 13:09 UTC, Michael Weghorn
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Weghorn 2020-11-11 13:07:51 UTC
Created attachment 133230 [details]
Small sample program

SUMMARY

When drawing a frame border/outline using

    QApplication::style()->drawPrimitive(QStyle::PE_Frame,...)

with the Breeze style, the border is not drawn at the outer edge of the rectangle being passed, but an additional pixel "too far inside" of the rectangle.

This e.g. leads to borders not being shown correctly when LibreOffice is used with the qt5/kf5 integration (s. details below.)


STEPS TO REPRODUCE

1. Compile attached sample program "main.cpp"
2. run it (it creates an image file in /tmp/frame.png)
3. open the file /tmp/frame.png and check the position and total size of the rectangle, including the border

OBSERVED RESULT

* The rectangle border starts at pixel (6,6).
* The rectangle (including the border) has a width and height of 8 pixels.

EXPECTED RESULT

Since the rect that was specified in the option as a 'QRect(5, 5, 10, 10)':

* The rectangle border should start at pixel (5,5).
* The rectangle (including the border) should have a width of and height of 10 pixels

SOFTWARE/OS VERSIONS

Operating System: Debian GNU/Linux 
KDE Plasma Version: 5.17.5
KDE Frameworks Version: 5.74.0
Qt Version: 5.15.1
Kernel Version: 5.9.0-1-amd64
OS Type: 64-bit
Processors: 12 × Intel® Core™ i7-9850H CPU @ 2.60GHz
Memory: 62.4 GiB of RAM

ADDITIONAL INFORMATION

* The border is placed as expected when using the Fusion style instead (e.g. by setting env variable QT_STYLE_OVERRIDE=Fusion).

* The border is placed as expected when using a QStyle::PE_FrameWindow primitive instead of QStyle::PE_Frame.

* Tested with Breeze style 5.17.5 from Debian packages as well as current git master (as of c06b43dc99d68543f6f100517883620f60028f9c).

* This bug report is based on LibreOffice bug reports https://bugs.documentfoundation.org/show_bug.cgi?id=138010 and https://bugs.documentfoundation.org/show_bug.cgi?id=137956. The issue described here leads to various borders not being shown when LibreOffice is used with the qt5/kf5 integration and the Breeze style. From my analysis, it's a bug in the Breeze theme, I plan to submit a merge request to fix this soon.
Comment 1 Michael Weghorn 2020-11-11 13:08:15 UTC
Created attachment 133231 [details]
Image created by running the sample program
Comment 2 Michael Weghorn 2020-11-11 13:09:23 UTC
Created attachment 133232 [details]
Screenshot of enlarged image (where exact pixels can be seen more easily)
Comment 3 Michael Weghorn 2020-11-11 13:35:10 UTC
(In reply to Michael Weghorn from comment #0)
> From my analysis,
> it's a bug in the Breeze theme, I plan to submit a merge request to fix this
> soon.

-> https://invent.kde.org/plasma/breeze/-/merge_requests/51
Comment 4 Michael Weghorn 2020-11-11 19:50:42 UTC
Git commit 7e678c344b3d931acafe495a1e19d23199aacca7 by Michael Weghorn.
Committed on 11/11/2020 at 13:09.
Pushed by ngraham into branch 'master'.

Draw frame outline at the outer edge, not a pixel further inside

The documentation for 'QPainter::drawRoundedRect' [1]
says:

"A filled rectangle has a size of rect.size(). A stroked
rectangle has a size of rect.size() plus the pen width."

Therefore, the frame rect passed to that method needs to
be adjusted according to the pen width for the case where
the rect is stroked (i.e. an outline exists), and no
adjustement is needed when the rect is not stroked so
that

    [size of rect] + [outline width] = [wanted total size]

The default pen size is 1 (which is also the value
of 'PenWidth::Frame' used to calculate the radius for the
outline a few lines further down).

For the case that an outline exists, the adjustment of
the rect already happens in the call to 'Helper::strokedRect',
so there is no need for reducing the rect by one additional
pixel on each side, which resulted in the frame border
unnecessarily not being right at the inner edge of the
rect, but one additional pixel "further inside".

It looks like the additional adjustment was originally added
by commit 3dbcea7e59cba2ae3afa1a66234502afa7d476d1
("Changed frame width to 2, to cope with focus rect.",
2014-07-30), later adapted by  commit
f288c34c3e0f16217538453620f94fb637a20d6c
("Render 2px focused outline *inside* frames rather than outside",
2014-08-11) and commit 2985b4cb6b036a3fcbea6ba6c9fc79eb90f528dc
("use one pixel for focus frame instead of 2", 2014-09-22).

While 'Metrics::Frame_FrameWidth' still has the value 2,
it is not used here at all, so the default pen width of 1
applies.

Therefore, drop the extra adjustment in order for the
stroke to be drawn right at the edge of the rect.

[1] https://doc.qt.io/qt-5/qpainter.html#drawRoundedRect

M  +1    -1    kstyle/breezehelper.cpp

https://invent.kde.org/plasma/breeze/commit/7e678c344b3d931acafe495a1e19d23199aacca7