Commit 9b34bfb4 authored by Oliver Sander's avatar Oliver Sander Committed by Albert Astals Cid

Make page boundary rendering more robust

Okular renders a simple 'shadow' at the right and the bottom of each
page.  The code for this is a bit fragile:  After the page is rendered,
Okular paints a black outline, and then the shadow.  The shadow is
a hand-implemented gradient, painted line by line.  Finally, the
remaining area is painted in the background color.  No pixel is
ever touched twice.  Unfortunately, the code is buggy, and in hidpi /
fractional scaling situations, some pixels are never touched.
This results in rendering glitches as reported in

  https://bugs.kde.org/show_bug.cgi?id=383943

Instead of trying to fix the previous approach, this patch makes the
code more robust by changing the order of the painting operations.
After painting the page, the code now first paints the background,
which is now enlarged to cover everything off the page.  Finally,
the black outline and shadow are drawn on the previously drawn
background.  This makes sures that no pixel is ever left uninitialized.
It also allows to simplify the shadow drawing operation a bit.

BUG: 383943
parent f681fb0e
......@@ -3500,55 +3500,24 @@ void PageView::drawDocumentOnPainter( const QRect & contentsRect, QPainter * p )
else
backColor = viewport()->palette().color( QPalette::Dark );
// when checking if an Item is contained in contentsRect, instead of
// growing PageViewItems rects (for keeping outline into account), we
// grow the contentsRect
QRect checkRect = contentsRect;
checkRect.adjust( -3, -3, 1, 1 );
// create a region from which we'll subtract painted rects
QRegion remainingArea( contentsRect );
// This loop draws the actual pages
// iterate over all items painting the ones intersecting contentsRect
for ( const PageViewItem * item : qAsConst( d->items ) )
{
// check if a piece of the page intersects the contents rect
if ( !item->isVisible() || !item->croppedGeometry().intersects( checkRect ) )
if ( !item->isVisible() || !item->croppedGeometry().intersects( contentsRect ) )
continue;
// get item and item's outline geometries
QRect itemGeometry = item->croppedGeometry(),
outlineGeometry = itemGeometry;
outlineGeometry.adjust( -1, -1, 3, 3 );
QRect itemGeometry = item->croppedGeometry();
// move the painter to the top-left corner of the real page
p->save();
p->translate( itemGeometry.left(), itemGeometry.top() );
// draw the page outline (black border and 2px bottom-right shadow)
if ( !itemGeometry.contains( contentsRect ) )
{
int itemWidth = itemGeometry.width(),
itemHeight = itemGeometry.height();
// draw simple outline
p->setPen( Qt::black );
p->drawRect( -1, -1, itemWidth + 1, itemHeight + 1 );
// draw bottom/right gradient
static const int levels = 2;
int r = backColor.red() / (levels + 2) + 6,
g = backColor.green() / (levels + 2) + 6,
b = backColor.blue() / (levels + 2) + 6;
for ( int i = 0; i < levels; i++ )
{
p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) );
p->drawLine( i, i + itemHeight + 1, i + itemWidth + 1, i + itemHeight + 1 );
p->drawLine( i + itemWidth + 1, i, i + itemWidth + 1, i + itemHeight );
p->setPen( backColor );
p->drawLine( -1, i + itemHeight + 1, i - 1, i + itemHeight + 1 );
p->drawLine( i + itemWidth + 1, -1, i + itemWidth + 1, i - 1 );
}
}
// draw the page using the PagePainter with all flags active
if ( contentsRect.intersects( itemGeometry ) )
{
......@@ -3567,13 +3536,56 @@ void PageView::drawDocumentOnPainter( const QRect & contentsRect, QPainter * p )
}
// remove painted area from 'remainingArea' and restore painter
remainingArea -= outlineGeometry.intersected( contentsRect );
remainingArea -= itemGeometry;
p->restore();
}
// fill the visible area around the page with the background color
for (const QRect& backRect : remainingArea )
p->fillRect( backRect, backColor );
// take outline and shadow into account when testing whether a repaint is necessary
auto dpr = devicePixelRatioF();
QRect checkRect = contentsRect;
checkRect.adjust( -3, -3, 1, 1 );
// iterate over all items painting a black outline and a simple bottom/right gradient
for ( const PageViewItem * item : qAsConst( d->items ) )
{
// check if a piece of the page intersects the contents rect
if ( !item->isVisible() || !item->croppedGeometry().intersects( checkRect ) )
continue;
// get item and item's outline geometries
QRect itemGeometry = item->croppedGeometry();
// move the painter to the top-left corner of the real page
p->save();
p->translate( itemGeometry.left(), itemGeometry.top() );
// draw the page outline (black border and 2px bottom-right shadow)
if ( !itemGeometry.contains( contentsRect ) )
{
int itemWidth = itemGeometry.width();
int itemHeight = itemGeometry.height();
// draw simple outline
p->setPen( Qt::black );
p->drawRect( -1, -1, itemWidth + 1, itemHeight + 1 );
// draw bottom/right gradient
static const int levels = 2;
int r = backColor.red() / (levels + 2) + 6,
g = backColor.green() / (levels + 2) + 6,
b = backColor.blue() / (levels + 2) + 6;
for ( int i = 0; i < levels; i++ )
{
p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) );
p->drawLine( i, i + itemHeight + 1, i + itemWidth + 1, i + itemHeight + 1 );
p->drawLine( i + itemWidth + 1, i, i + itemWidth + 1, i + itemHeight );
}
}
p->restore();
}
}
void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight )
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment