bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / qt5 / QtGraphics_GDI.cxx
blob28bab34a7cca2aa27559f63116a5554302026fef
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <QtGraphics.hxx>
22 #include <QtBitmap.hxx>
23 #include <QtPainter.hxx>
25 #include <sal/log.hxx>
27 #include <QtGui/QPainter>
28 #include <QtGui/QScreen>
29 #include <QtGui/QWindow>
30 #include <QtWidgets/QWidget>
32 #include <numeric>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 QtGraphicsBackend::QtGraphicsBackend(QtFrame* pFrame, QImage* pQImage)
37 : m_pFrame(pFrame)
38 , m_pQImage(pQImage)
39 , m_oLineColor(std::in_place, 0x00, 0x00, 0x00)
40 , m_oFillColor(std::in_place, 0xFF, 0xFF, 0XFF)
41 , m_eCompositionMode(QPainter::CompositionMode_SourceOver)
43 ResetClipRegion();
46 QtGraphicsBackend::~QtGraphicsBackend() {}
48 const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5);
50 static void AddPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolygon& rPolygon,
51 bool bClosePath, bool bPixelSnap, bool bLineDraw)
53 const int nPointCount = rPolygon.count();
54 // short circuit if there is nothing to do
55 if (nPointCount == 0)
56 return;
58 const bool bHasCurves = rPolygon.areControlPointsUsed();
59 for (int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++)
61 int nClosedIdx = nPointIdx;
62 if (nPointIdx >= nPointCount)
64 // prepare to close last curve segment if needed
65 if (bClosePath && (nPointIdx == nPointCount))
66 nClosedIdx = 0;
67 else
68 break;
71 basegfx::B2DPoint aPoint = rPolygon.getB2DPoint(nClosedIdx);
73 if (bPixelSnap)
75 // snap device coordinates to full pixels
76 aPoint.setX(basegfx::fround(aPoint.getX()));
77 aPoint.setY(basegfx::fround(aPoint.getY()));
80 if (bLineDraw)
81 aPoint += aHalfPointOfs;
82 if (!nPointIdx)
84 // first point => just move there
85 rPath.moveTo(aPoint.getX(), aPoint.getY());
86 continue;
89 bool bPendingCurve = false;
90 if (bHasCurves)
92 bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx);
93 bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx);
96 if (!bPendingCurve) // line segment
97 rPath.lineTo(aPoint.getX(), aPoint.getY());
98 else // cubic bezier segment
100 basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint(nPrevIdx);
101 basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint(nClosedIdx);
102 if (bLineDraw)
104 aCP1 += aHalfPointOfs;
105 aCP2 += aHalfPointOfs;
107 rPath.cubicTo(aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(),
108 aPoint.getY());
112 if (bClosePath)
113 rPath.closeSubpath();
116 static bool AddPolyPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolyPolygon& rPolyPoly,
117 bool bPixelSnap, bool bLineDraw)
119 if (rPolyPoly.count() == 0)
120 return false;
121 for (auto const& rPolygon : rPolyPoly)
123 AddPolygonToPath(rPath, rPolygon, true, bPixelSnap, bLineDraw);
125 return true;
128 void QtGraphicsBackend::setClipRegion(const vcl::Region& rRegion)
130 if (rRegion.IsRectangle())
132 m_aClipRegion = toQRect(rRegion.GetBoundRect());
133 if (!m_aClipPath.isEmpty())
135 QPainterPath aPath;
136 m_aClipPath.swap(aPath);
139 else if (!rRegion.HasPolyPolygonOrB2DPolyPolygon())
141 QRegion aQRegion;
142 RectangleVector aRectangles;
143 rRegion.GetRegionRectangles(aRectangles);
144 for (const auto& rRect : aRectangles)
145 aQRegion += toQRect(rRect);
146 m_aClipRegion = aQRegion;
147 if (!m_aClipPath.isEmpty())
149 QPainterPath aPath;
150 m_aClipPath.swap(aPath);
153 else
155 QPainterPath aPath;
156 const basegfx::B2DPolyPolygon aPolyClip(rRegion.GetAsB2DPolyPolygon());
157 AddPolyPolygonToPath(aPath, aPolyClip, !getAntiAlias(), false);
158 m_aClipPath.swap(aPath);
159 if (!m_aClipRegion.isEmpty())
161 QRegion aRegion;
162 m_aClipRegion.swap(aRegion);
167 void QtGraphicsBackend::ResetClipRegion()
169 if (m_pQImage)
170 m_aClipRegion = QRegion(m_pQImage->rect());
171 else
172 m_aClipRegion = QRegion();
173 if (!m_aClipPath.isEmpty())
175 QPainterPath aPath;
176 m_aClipPath.swap(aPath);
180 void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY)
182 QtPainter aPainter(*this);
183 aPainter.drawPoint(nX, nY);
184 aPainter.update(nX, nY, 1, 1);
187 void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color nColor)
189 QtPainter aPainter(*this);
190 aPainter.setPen(toQColor(nColor));
191 aPainter.setPen(Qt::SolidLine);
192 aPainter.drawPoint(nX, nY);
193 aPainter.update(nX, nY, 1, 1);
196 void QtGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
198 QtPainter aPainter(*this);
199 aPainter.drawLine(nX1, nY1, nX2, nY2);
201 if (nX1 > nX2)
202 std::swap(nX1, nX2);
203 if (nY1 > nY2)
204 std::swap(nY1, nY2);
205 aPainter.update(nX1, nY1, nX2 - nX1 + 1, nY2 - nY1 + 1);
208 void QtGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
209 tools::Long nHeight)
211 if (!m_oFillColor && !m_oLineColor)
212 return;
214 QtPainter aPainter(*this, true);
215 if (m_oFillColor)
216 aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush());
217 if (m_oLineColor)
218 aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1);
219 aPainter.update(nX, nY, nWidth, nHeight);
222 void QtGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry)
224 if (0 == nPoints)
225 return;
227 QtPainter aPainter(*this);
228 QPoint* pPoints = new QPoint[nPoints];
229 QPoint aTopLeft(pPtAry->getX(), pPtAry->getY());
230 QPoint aBottomRight = aTopLeft;
231 for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry)
233 pPoints[i] = QPoint(pPtAry->getX(), pPtAry->getY());
234 if (pPtAry->getX() < aTopLeft.x())
235 aTopLeft.setX(pPtAry->getX());
236 if (pPtAry->getY() < aTopLeft.y())
237 aTopLeft.setY(pPtAry->getY());
238 if (pPtAry->getX() > aBottomRight.x())
239 aBottomRight.setX(pPtAry->getX());
240 if (pPtAry->getY() > aBottomRight.y())
241 aBottomRight.setY(pPtAry->getY());
243 aPainter.drawPolyline(pPoints, nPoints);
244 delete[] pPoints;
245 aPainter.update(QRect(aTopLeft, aBottomRight));
248 void QtGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry)
250 QtPainter aPainter(*this, true);
251 QPolygon aPolygon(nPoints);
252 for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry)
253 aPolygon.setPoint(i, pPtAry->getX(), pPtAry->getY());
254 aPainter.drawPolygon(aPolygon);
255 aPainter.update(aPolygon.boundingRect());
258 void QtGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints,
259 const Point** ppPtAry)
261 // ignore invisible polygons
262 if (!m_oFillColor && !m_oLineColor)
263 return;
265 QPainterPath aPath;
266 for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++)
268 const sal_uInt32 nPoints = pPoints[nPoly];
269 if (nPoints > 1)
271 const Point* pPtAry = ppPtAry[nPoly];
272 aPath.moveTo(pPtAry->getX(), pPtAry->getY());
273 pPtAry++;
274 for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++)
275 aPath.lineTo(pPtAry->getX(), pPtAry->getY());
276 aPath.closeSubpath();
280 QtPainter aPainter(*this, true);
281 aPainter.drawPath(aPath);
282 aPainter.update(aPath.boundingRect());
285 bool QtGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
286 const basegfx::B2DPolyPolygon& rPolyPolygon,
287 double fTransparency)
289 // ignore invisible polygons
290 if (!m_oFillColor && !m_oLineColor)
291 return true;
292 if ((fTransparency >= 1.0) || (fTransparency < 0))
293 return true;
295 // Fallback: Transform to DeviceCoordinates
296 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
297 aPolyPolygon.transform(rObjectToDevice);
299 QPainterPath aPath;
300 // ignore empty polygons
301 if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAlias(), m_oLineColor.has_value()))
302 return true;
304 QtPainter aPainter(*this, true, 255 * (1.0 - fTransparency));
305 aPainter.drawPath(aPath);
306 aPainter.update(aPath.boundingRect());
307 return true;
310 bool QtGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
311 const PolyFlags* /*pFlgAry*/)
313 return false;
316 bool QtGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
317 const PolyFlags* /*pFlgAry*/)
319 return false;
322 bool QtGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/,
323 const Point* const* /*pPtAry*/,
324 const PolyFlags* const* /*pFlgAry*/)
326 return false;
329 bool QtGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
330 const basegfx::B2DPolygon& rPolyLine, double fTransparency,
331 double fLineWidth,
332 const std::vector<double>* pStroke, // MM01
333 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap,
334 double fMiterMinimumAngle, bool bPixelSnapHairline)
336 if (!m_oFillColor && !m_oLineColor)
338 return true;
341 // MM01 check done for simple reasons
342 if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
344 return true;
347 // MM01 need to do line dashing as fallback stuff here now
348 const double fDotDashLength(
349 nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
350 const bool bStrokeUsed(0.0 != fDotDashLength);
351 assert(!bStrokeUsed || (bStrokeUsed && pStroke));
352 basegfx::B2DPolyPolygon aPolyPolygonLine;
354 if (bStrokeUsed)
356 // apply LineStyle
357 basegfx::utils::applyLineDashing(rPolyLine, // source
358 *pStroke, // pattern
359 &aPolyPolygonLine, // target for lines
360 nullptr, // target for gaps
361 fDotDashLength); // full length if available
363 else
365 // no line dashing, just copy
366 aPolyPolygonLine.append(rPolyLine);
369 // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
370 aPolyPolygonLine.transform(rObjectToDevice);
371 if (bPixelSnapHairline)
373 aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
376 // tdf#124848 get correct LineWidth in discrete coordinates,
377 if (fLineWidth == 0) // hairline
378 fLineWidth = 1.0;
379 else // Adjust line width for object-to-device scale.
380 fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
382 // setup poly-polygon path
383 QPainterPath aPath;
385 // MM01 todo - I assume that this is OKAY to be done in one run for Qt,
386 // but this NEEDS to be checked/verified
387 for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
389 const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
390 AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true);
393 QtPainter aPainter(*this, false, 255 * (1.0 - fTransparency));
395 // setup line attributes
396 QPen aPen = aPainter.pen();
397 aPen.setWidth(fLineWidth);
399 switch (eLineJoin)
401 case basegfx::B2DLineJoin::Bevel:
402 aPen.setJoinStyle(Qt::BevelJoin);
403 break;
404 case basegfx::B2DLineJoin::Round:
405 aPen.setJoinStyle(Qt::RoundJoin);
406 break;
407 case basegfx::B2DLineJoin::NONE:
408 case basegfx::B2DLineJoin::Miter:
409 aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0));
410 aPen.setJoinStyle(Qt::MiterJoin);
411 break;
414 switch (eLineCap)
416 default: // css::drawing::LineCap_BUTT:
417 aPen.setCapStyle(Qt::FlatCap);
418 break;
419 case css::drawing::LineCap_ROUND:
420 aPen.setCapStyle(Qt::RoundCap);
421 break;
422 case css::drawing::LineCap_SQUARE:
423 aPen.setCapStyle(Qt::SquareCap);
424 break;
427 aPainter.setPen(aPen);
428 aPainter.drawPath(aPath);
429 aPainter.update(aPath.boundingRect());
430 return true;
433 bool QtGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolyPolygon*/,
434 const Gradient& /*rGradient*/)
436 return false;
439 bool QtGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/,
440 SalGradient const& /*rGradient*/)
442 return false;
445 void QtGraphicsBackend::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage)
447 QtPainter aPainter(*this);
448 QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
449 QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
450 aPainter.drawImage(aDestRect, rImage, aSrcRect);
451 aPainter.update(aDestRect);
454 void QtGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX,
455 tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight,
456 bool /*bWindowInvalidate*/)
458 if (nDestX == nSrcX && nDestY == nSrcY)
459 return;
461 SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
463 QImage* pImage = m_pQImage;
464 QImage aImage = pImage->copy(aTR.mnSrcX, aTR.mnSrcY, aTR.mnSrcWidth, aTR.mnSrcHeight);
465 pImage = &aImage;
466 aTR.mnSrcX = 0;
467 aTR.mnSrcY = 0;
469 drawScaledImage(aTR, *pImage);
472 void QtGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics)
474 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
475 || rPosAry.mnDestHeight <= 0)
476 return;
478 QImage aImage, *pImage;
479 SalTwoRect aPosAry = rPosAry;
481 if (!pSrcGraphics)
483 pImage = m_pQImage;
484 aImage
485 = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
486 pImage = &aImage;
487 aPosAry.mnSrcX = 0;
488 aPosAry.mnSrcY = 0;
490 else
491 pImage = static_cast<QtGraphics*>(pSrcGraphics)->getQImage();
493 drawScaledImage(aPosAry, *pImage);
496 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
498 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
499 || rPosAry.mnDestHeight <= 0)
500 return;
502 const QImage* pImage = static_cast<const QtBitmap*>(&rSalBitmap)->GetQImage();
504 assert(pImage);
506 drawScaledImage(rPosAry, *pImage);
509 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
510 const SalBitmap& /*rTransparentBitmap*/)
512 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
513 || rPosAry.mnDestHeight <= 0)
514 return;
516 assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth);
517 assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight);
520 void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
521 Color /*nMaskColor*/)
523 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
524 || rPosAry.mnDestHeight <= 0)
525 return;
527 assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth);
528 assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight);
531 std::shared_ptr<SalBitmap> QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY,
532 tools::Long nWidth, tools::Long nHeight)
534 return std::make_shared<QtBitmap>(m_pQImage->copy(nX, nY, nWidth, nHeight));
537 Color QtGraphicsBackend::getPixel(tools::Long nX, tools::Long nY)
539 return Color(ColorTransparency, m_pQImage->pixel(nX, nY));
542 void QtGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth,
543 tools::Long nHeight, SalInvert nFlags)
545 QtPainter aPainter(*this);
546 if (SalInvert::N50 & nFlags)
548 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
549 QBrush aBrush(Qt::white, Qt::Dense4Pattern);
550 aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush);
552 else
554 if (SalInvert::TrackFrame & nFlags)
556 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
557 QPen aPen(Qt::white);
558 aPen.setStyle(Qt::DotLine);
559 aPainter.setPen(aPen);
560 aPainter.drawRect(nX, nY, nWidth, nHeight);
562 else
564 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
565 aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white);
568 aPainter.update(nX, nY, nWidth, nHeight);
571 void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
572 SalInvert /*nFlags*/)
576 bool QtGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/,
577 tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/)
579 return false;
582 bool QtGraphicsBackend::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/)
584 return false;
587 bool QtGraphicsBackend::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/,
588 const SalBitmap& /*rMaskBitmap*/,
589 const SalBitmap& /*rAlphaBitmap*/)
591 return false;
594 static QImage getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap)
596 assert(rSourceBitmap.GetSize() == rAlphaBitmap.GetSize());
597 assert(rAlphaBitmap.GetBitCount() == 8 || rAlphaBitmap.GetBitCount() == 1);
599 QImage aAlphaMask = *static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage();
600 aAlphaMask.invertPixels();
602 const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
603 QImage aImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
604 aImage.setAlphaChannel(aAlphaMask);
605 return aImage;
608 bool QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap,
609 const SalBitmap& rAlphaBitmap)
611 drawScaledImage(rPosAry, getAlphaImage(rSourceBitmap, rAlphaBitmap));
612 return true;
615 bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
616 const basegfx::B2DPoint& rX,
617 const basegfx::B2DPoint& rY,
618 const SalBitmap& rSourceBitmap,
619 const SalBitmap* pAlphaBitmap, double fAlpha)
621 QImage aImage;
622 if (!pAlphaBitmap)
623 aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
624 else
625 aImage = getAlphaImage(rSourceBitmap, *pAlphaBitmap);
627 const basegfx::B2DVector aXRel = rX - rNull;
628 const basegfx::B2DVector aYRel = rY - rNull;
630 QtPainter aPainter(*this);
631 aPainter.setOpacity(fAlpha);
632 aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(),
633 aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(),
634 rNull.getX(), rNull.getY()));
635 aPainter.drawImage(QPoint(0, 0), aImage);
636 aPainter.update(aImage.rect());
637 return true;
640 bool QtGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; }
642 bool QtGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
643 tools::Long nHeight, sal_uInt8 nTransparency)
645 if (!m_oFillColor && !m_oLineColor)
646 return true;
647 assert(nTransparency <= 100);
648 if (nTransparency > 100)
649 nTransparency = 100;
650 QtPainter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100));
651 if (m_oFillColor)
652 aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush());
653 if (m_oLineColor)
654 aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1);
655 aPainter.update(nX, nY, nWidth, nHeight);
656 return true;
659 sal_uInt16 QtGraphicsBackend::GetBitCount() const { return getFormatBits(m_pQImage->format()); }
661 tools::Long QtGraphicsBackend::GetGraphicsWidth() const { return m_pQImage->width(); }
663 void QtGraphicsBackend::SetLineColor() { m_oLineColor = std::nullopt; }
665 void QtGraphicsBackend::SetLineColor(Color nColor) { m_oLineColor = nColor; }
667 void QtGraphicsBackend::SetFillColor() { m_oFillColor = std::nullopt; }
669 void QtGraphicsBackend::SetFillColor(Color nColor) { m_oFillColor = nColor; }
671 void QtGraphicsBackend::SetXORMode(bool bSet, bool)
673 if (bSet)
674 m_eCompositionMode = QPainter::CompositionMode_Xor;
675 else
676 m_eCompositionMode = QPainter::CompositionMode_SourceOver;
679 void QtGraphicsBackend::SetROPLineColor(SalROPColor /*nROPColor*/) {}
681 void QtGraphicsBackend::SetROPFillColor(SalROPColor /*nROPColor*/) {}
683 bool QtGraphicsBackend::supportsOperation(OutDevSupportType eType) const
685 switch (eType)
687 case OutDevSupportType::B2DDraw:
688 case OutDevSupportType::TransparentRect:
689 return true;
690 default:
691 return false;
695 void QtGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
697 char* pForceDpi;
698 if ((pForceDpi = getenv("SAL_FORCEDPI")))
700 OString sForceDPI(pForceDpi);
701 rDPIX = rDPIY = sForceDPI.toInt32();
702 return;
705 if (!m_pFrame)
706 return;
708 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
709 QScreen* pScreen = m_pFrame->GetQWidget()->screen();
710 #else
711 if (!m_pFrame->GetQWidget()->window()->windowHandle())
712 return;
714 QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen();
715 #endif
716 rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5;
717 rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5;
720 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */