From f9981df2939eadd18223bc5e20af99373db133f1 Mon Sep 17 00:00:00 2001
From: Khaled Hosny <khaledhosny@eglug.org>
Date: Sun, 1 May 2016 02:44:10 +0200
Subject: [PATCH] Improve Canvas drawing on Hi-DPI screens
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Set Qt::AA_UseHighDpiPixmaps to allow for Hi-DPI QPixmaps
* Multiply the size of the multitude of intermediate QImage’s and
  QPixmaps we create for the Canvas by its devicePixelFactor, and set
  their devicePixelFactor as well.
* Set the device scale of Cairo surface to that of the QPixmap we are
  drawing it into.
---
 scribus/canvas.cpp     | 46 ++++++++++++++++++++++++++--------------------
 scribus/canvas.h       |  5 +++++
 scribus/scpainter.cpp  |  1 +
 scribus/scribusapp.cpp |  2 +-
 4 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/scribus/canvas.cpp b/scribus/canvas.cpp
index ab19ccc..2af8452 100644
--- a/scribus/canvas.cpp
+++ b/scribus/canvas.cpp
@@ -663,7 +663,7 @@ bool Canvas::adjustBuffer()
 	{
 //		qDebug() << "adjust buffer: invalid buffer, viewport" << viewport;
 		m_bufferRect = viewport;
-		m_buffer = QPixmap(m_bufferRect.width(), m_bufferRect.height());
+		m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
 		fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
 		ret = true;
 #if DRAW_DEBUG_LINES
@@ -691,8 +691,7 @@ bool Canvas::adjustBuffer()
 		{
 //			qDebug() << "adjust buffer: fresh buffer" << m_bufferRect << "-->" << newRect;
 			m_bufferRect = newRect;
-// 			m_buffer = QImage(m_bufferRect.width(), m_bufferRect.height(), QImage::Format_ARGB32);
-			m_buffer = QPixmap(m_bufferRect.width(), m_bufferRect.height());
+			m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
 			fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
 			ret = true;
 #if DRAW_DEBUG_LINES
@@ -706,8 +705,7 @@ bool Canvas::adjustBuffer()
 		else
 		{
 			// copy buffer:
-// 			QImage newBuffer(newRect.width(), newRect.height(), QImage::Format_ARGB32);
-			QPixmap newBuffer(newRect.width(), newRect.height());
+			QPixmap newBuffer = createPixmap(newRect.width(), newRect.height());
 			QPainter p(&newBuffer);
 			int xpos = m_bufferRect.x() - newRect.x();
 			int ypos = m_bufferRect.y() - newRect.y();
@@ -735,8 +733,8 @@ bool Canvas::adjustBuffer()
 			{
 				height = newRect.height() - ypos;
 			}
-// 			p.drawImage(xpos, ypos, m_buffer, x, y,  width + 1, height + 1); // FIXME: == params drawPixmap?
-			p.drawPixmap(xpos, ypos, m_buffer, x, y,  width + 1, height + 1);
+
+			drawPixmap(p, xpos, ypos, m_buffer, x, y, width + 1, height + 1);
 #if DRAW_DEBUG_LINES
 			p.setPen(Qt::blue);
 			p.drawLine(xpos, ypos+height/2, xpos+width/2, ypos);
@@ -818,11 +816,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 #endif
 	// fill buffer if necessary
 	bool bufferFilled = adjustBuffer();
-	// It is ugly, but until we figure out why drawing directly on the 
-	// widget is so slow, it saves us a Cray! - pm
-	QPixmap tmpImg(p->rect().size());
-	QPainter qp(&tmpImg);
-	qp.translate(-p->rect().x(), -p->rect().y());
+	QPainter qp(this);
 	switch (m_renderMode)
 	{
 		case RENDER_NORMAL:
@@ -850,8 +844,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 			int hV = p->rect().height();
 			if (hV > 0 && wV > 0)
 			{
-// 				qp.drawImage(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
-				qp.drawPixmap(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
+				drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
 #if DRAW_DEBUG_LINES
 //				qDebug() << "normal rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
 				qp.setPen(Qt::blue);
@@ -904,9 +897,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 #endif
 				if (hV > 0 && wV > 0)
 				{
-// 					qp.drawImage(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
-					
-					qp.drawPixmap(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
+					drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
 	#if DRAW_DEBUG_LINES
 //					qDebug() << "buffered rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
 					qp.setPen(Qt::green);
@@ -948,8 +939,6 @@ void Canvas::paintEvent ( QPaintEvent * p )
 	// does mode specific rendering, currently selection in legacymode and nodes in nodeedit
 	m_view->m_canvasMode->drawControls(&qp);
 	m_view->m_canvasMode->drawSnapLine(&qp);
-	QPainter tp(this);
-	tp.drawPixmap(p->rect(), tmpImg, tmpImg.rect());
 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
 	t6 = t.elapsed();
 	qDebug()<<dmode<<t1<<t2<<t3<<t4<<t5<<t6<<"-" <<t1+t2+t3+t4+t5+t6;
@@ -969,7 +958,8 @@ void Canvas::drawContents(QPainter *psx, int clipx, int clipy, int clipw, int cl
 // 	qDebug() << "Canvas::drawContents" << clipx << clipy << clipw << cliph<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
 	uint docPagesCount=m_doc->Pages->count();
 	ScPainter *painter=0;
-	QImage img = QImage(clipw, cliph, QImage::Format_ARGB32_Premultiplied);
+	QImage img = QImage(clipw * devicePixelRatio(), cliph * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied);
+	img.setDevicePixelRatio(devicePixelRatio());
 	painter = new ScPainter(&img, img.width(), img.height(), 1.0, 0);
 	painter->clear(palette().color(QPalette::Window));
 	painter->newPath();
@@ -2411,6 +2401,22 @@ void Canvas::calculateFrameLinkPoints(PageItem *pi1, PageItem *pi2, FPoint & sta
 	end.transform(pi2->xPos(), pi2->yPos(), pi2->rotation(), 1, 1, false);
 }
 
+QPixmap Canvas::createPixmap(double w, double h)
+{
+	QPixmap p(w * devicePixelRatio(), h * devicePixelRatio());
+	p.setDevicePixelRatio(devicePixelRatio());
+	return p;
+}
+
+void Canvas::drawPixmap(QPainter& painter, double x, double y, const QPixmap& pixmap, double sx, double sy, double sw, double sh)
+{
+	sx *= devicePixelRatio();
+	sy *= devicePixelRatio();
+	sw *= devicePixelRatio();
+	sh *= devicePixelRatio();
+	painter.drawPixmap(x, y, pixmap, sx, sy, sw, sh);
+}
+
 void Canvas::displayXYHUD(QPoint m)
 {
 	if (!PrefsManager::instance()->appPrefs.displayPrefs.showMouseCoordinates)
diff --git a/scribus/canvas.h b/scribus/canvas.h
index 1501532..5aeaf7a 100644
--- a/scribus/canvas.h
+++ b/scribus/canvas.h
@@ -260,6 +260,11 @@ private:
 	void getLinkedFrames(PageItem* currItem);
 	void getClipPathForPages(FPointArray* PoLine);
 	void calculateFrameLinkPoints(PageItem* pi1, PageItem* pi2, FPoint& start, FPoint& end);
+
+	// create a potentially hidpi pixmap
+	QPixmap createPixmap(double w, double h);
+	// draw a potentially hidpi pixmap
+	void drawPixmap(QPainter &painter, double x, double y, const QPixmap &pixmap, double sx, double sy, double sw, double sh);
 		
 private:
 	ScribusDoc* m_doc;
diff --git a/scribus/scpainter.cpp b/scribus/scpainter.cpp
index 7b36813..19cdf15 100644
--- a/scribus/scpainter.cpp
+++ b/scribus/scpainter.cpp
@@ -52,6 +52,7 @@ ScPainter::ScPainter( QImage *target, unsigned int w, unsigned int h, double tra
 	m_matrix = QTransform();
 	m_zoomStack.clear();
 	cairo_surface_t *img = cairo_image_surface_create_for_data(m_image->bits(), CAIRO_FORMAT_ARGB32, w, h, w*4);
+	cairo_surface_set_device_scale(img, m_image->devicePixelRatio(), m_image->devicePixelRatio());
 	m_cr = cairo_create(img);
 	cairo_save( m_cr );
 	cairo_set_fill_rule (m_cr, CAIRO_FILL_RULE_EVEN_ODD);
diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp
index 486f478..800e1cb 100644
--- a/scribus/scribusapp.cpp
+++ b/scribus/scribusapp.cpp
@@ -110,7 +110,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv),
 	m_scDLMgr = 0;
 	m_ScCore = NULL;
 	initDLMgr();
-
+	setAttribute(Qt::AA_UseHighDpiPixmaps, true);
 }
 
 ScribusQApp::~ScribusQApp()
-- 
2.8.2

