Update git submodules
[LibreOffice.git] / vcl / qt5 / QtGraphics_GDI.cxx
blob2005de80f7ba660dd52f111d0013683bc21d9525
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 void 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;
292 if ((fTransparency >= 1.0) || (fTransparency < 0))
293 return;
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;
304 QtPainter aPainter(*this, true, 255 * (1.0 - fTransparency));
305 aPainter.drawPath(aPath);
306 aPainter.update(aPath.boundingRect());
309 bool QtGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
310 const PolyFlags* /*pFlgAry*/)
312 return false;
315 bool QtGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
316 const PolyFlags* /*pFlgAry*/)
318 return false;
321 bool QtGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/,
322 const Point* const* /*pPtAry*/,
323 const PolyFlags* const* /*pFlgAry*/)
325 return false;
328 bool QtGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
329 const basegfx::B2DPolygon& rPolyLine, double fTransparency,
330 double fLineWidth,
331 const std::vector<double>* pStroke, // MM01
332 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap,
333 double fMiterMinimumAngle, bool bPixelSnapHairline)
335 if (!m_oFillColor && !m_oLineColor)
337 return true;
340 // MM01 check done for simple reasons
341 if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
343 return true;
346 // MM01 need to do line dashing as fallback stuff here now
347 const double fDotDashLength(
348 nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
349 const bool bStrokeUsed(0.0 != fDotDashLength);
350 assert(!bStrokeUsed || (bStrokeUsed && pStroke));
351 basegfx::B2DPolyPolygon aPolyPolygonLine;
353 if (bStrokeUsed)
355 // apply LineStyle
356 basegfx::utils::applyLineDashing(rPolyLine, // source
357 *pStroke, // pattern
358 &aPolyPolygonLine, // target for lines
359 nullptr, // target for gaps
360 fDotDashLength); // full length if available
362 else
364 // no line dashing, just copy
365 aPolyPolygonLine.append(rPolyLine);
368 // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
369 aPolyPolygonLine.transform(rObjectToDevice);
370 if (bPixelSnapHairline)
372 aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
375 // tdf#124848 get correct LineWidth in discrete coordinates,
376 if (fLineWidth == 0) // hairline
377 fLineWidth = 1.0;
378 else // Adjust line width for object-to-device scale.
379 fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
381 // setup poly-polygon path
382 QPainterPath aPath;
384 // MM01 todo - I assume that this is OKAY to be done in one run for Qt,
385 // but this NEEDS to be checked/verified
386 for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
388 const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
389 AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true);
392 QtPainter aPainter(*this, false, 255 * (1.0 - fTransparency));
394 // setup line attributes
395 QPen aPen = aPainter.pen();
396 aPen.setWidth(fLineWidth);
398 switch (eLineJoin)
400 case basegfx::B2DLineJoin::Bevel:
401 aPen.setJoinStyle(Qt::BevelJoin);
402 break;
403 case basegfx::B2DLineJoin::Round:
404 aPen.setJoinStyle(Qt::RoundJoin);
405 break;
406 case basegfx::B2DLineJoin::NONE:
407 case basegfx::B2DLineJoin::Miter:
408 aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0));
409 aPen.setJoinStyle(Qt::MiterJoin);
410 break;
413 switch (eLineCap)
415 default: // css::drawing::LineCap_BUTT:
416 aPen.setCapStyle(Qt::FlatCap);
417 break;
418 case css::drawing::LineCap_ROUND:
419 aPen.setCapStyle(Qt::RoundCap);
420 break;
421 case css::drawing::LineCap_SQUARE:
422 aPen.setCapStyle(Qt::SquareCap);
423 break;
426 aPainter.setPen(aPen);
427 aPainter.drawPath(aPath);
428 aPainter.update(aPath.boundingRect());
429 return true;
432 bool QtGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolyPolygon*/,
433 const Gradient& /*rGradient*/)
435 return false;
438 bool QtGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/,
439 SalGradient const& /*rGradient*/)
441 return false;
444 void QtGraphicsBackend::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage)
446 QtPainter aPainter(*this);
447 QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
448 QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
449 aPainter.drawImage(aDestRect, rImage, aSrcRect);
450 aPainter.update(aDestRect);
453 void QtGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX,
454 tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight,
455 bool /*bWindowInvalidate*/)
457 if (nDestX == nSrcX && nDestY == nSrcY)
458 return;
460 SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
462 QImage* pImage = m_pQImage;
463 QImage aImage = pImage->copy(aTR.mnSrcX, aTR.mnSrcY, aTR.mnSrcWidth, aTR.mnSrcHeight);
464 pImage = &aImage;
465 aTR.mnSrcX = 0;
466 aTR.mnSrcY = 0;
468 drawScaledImage(aTR, *pImage);
471 void QtGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics)
473 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
474 || rPosAry.mnDestHeight <= 0)
475 return;
477 QImage aImage, *pImage;
478 SalTwoRect aPosAry = rPosAry;
480 if (!pSrcGraphics)
482 pImage = m_pQImage;
483 aImage
484 = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
485 pImage = &aImage;
486 aPosAry.mnSrcX = 0;
487 aPosAry.mnSrcY = 0;
489 else
490 pImage = static_cast<QtGraphics*>(pSrcGraphics)->getQImage();
492 drawScaledImage(aPosAry, *pImage);
495 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
497 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
498 || rPosAry.mnDestHeight <= 0)
499 return;
501 const QImage* pImage = static_cast<const QtBitmap*>(&rSalBitmap)->GetQImage();
503 assert(pImage);
505 drawScaledImage(rPosAry, *pImage);
508 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
509 const SalBitmap& /*rTransparentBitmap*/)
511 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
512 || rPosAry.mnDestHeight <= 0)
513 return;
515 assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth);
516 assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight);
519 void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
520 Color /*nMaskColor*/)
522 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
523 || rPosAry.mnDestHeight <= 0)
524 return;
526 assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth);
527 assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight);
530 std::shared_ptr<SalBitmap> QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY,
531 tools::Long nWidth, tools::Long nHeight)
533 return std::make_shared<QtBitmap>(m_pQImage->copy(nX, nY, nWidth, nHeight));
536 Color QtGraphicsBackend::getPixel(tools::Long nX, tools::Long nY)
538 return Color(ColorTransparency, m_pQImage->pixel(nX, nY));
541 void QtGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth,
542 tools::Long nHeight, SalInvert nFlags)
544 QtPainter aPainter(*this);
545 if (SalInvert::N50 & nFlags)
547 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
548 QBrush aBrush(Qt::white, Qt::Dense4Pattern);
549 aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush);
551 else
553 if (SalInvert::TrackFrame & nFlags)
555 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
556 QPen aPen(Qt::white);
557 aPen.setStyle(Qt::DotLine);
558 aPainter.setPen(aPen);
559 aPainter.drawRect(nX, nY, nWidth, nHeight);
561 else
563 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
564 aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white);
567 aPainter.update(nX, nY, nWidth, nHeight);
570 void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
571 SalInvert /*nFlags*/)
575 bool QtGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/,
576 tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/)
578 return false;
581 bool QtGraphicsBackend::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/)
583 return false;
586 bool QtGraphicsBackend::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/,
587 const SalBitmap& /*rMaskBitmap*/,
588 const SalBitmap& /*rAlphaBitmap*/)
590 return false;
593 static QImage getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap)
595 assert(rSourceBitmap.GetSize() == rAlphaBitmap.GetSize());
596 assert(rAlphaBitmap.GetBitCount() == 8 || rAlphaBitmap.GetBitCount() == 1);
598 QImage aAlphaMask = *static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage();
600 const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
601 QImage aImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
602 aImage.setAlphaChannel(aAlphaMask);
603 return aImage;
606 bool QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap,
607 const SalBitmap& rAlphaBitmap)
609 drawScaledImage(rPosAry, getAlphaImage(rSourceBitmap, rAlphaBitmap));
610 return true;
613 bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
614 const basegfx::B2DPoint& rX,
615 const basegfx::B2DPoint& rY,
616 const SalBitmap& rSourceBitmap,
617 const SalBitmap* pAlphaBitmap, double fAlpha)
619 QImage aImage;
620 if (!pAlphaBitmap)
621 aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
622 else
623 aImage = getAlphaImage(rSourceBitmap, *pAlphaBitmap);
625 const basegfx::B2DVector aXRel = rX - rNull;
626 const basegfx::B2DVector aYRel = rY - rNull;
628 QtPainter aPainter(*this);
629 aPainter.setOpacity(fAlpha);
630 aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(),
631 aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(),
632 rNull.getX(), rNull.getY()));
633 aPainter.drawImage(QPoint(0, 0), aImage);
634 aPainter.update(aImage.rect());
635 return true;
638 bool QtGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; }
640 bool QtGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
641 tools::Long nHeight, sal_uInt8 nTransparency)
643 if (!m_oFillColor && !m_oLineColor)
644 return true;
645 assert(nTransparency <= 100);
646 if (nTransparency > 100)
647 nTransparency = 100;
648 QtPainter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100));
649 if (m_oFillColor)
650 aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush());
651 if (m_oLineColor)
652 aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1);
653 aPainter.update(nX, nY, nWidth, nHeight);
654 return true;
657 sal_uInt16 QtGraphicsBackend::GetBitCount() const { return getFormatBits(m_pQImage->format()); }
659 tools::Long QtGraphicsBackend::GetGraphicsWidth() const { return m_pQImage->width(); }
661 void QtGraphicsBackend::SetLineColor() { m_oLineColor = std::nullopt; }
663 void QtGraphicsBackend::SetLineColor(Color nColor) { m_oLineColor = nColor; }
665 void QtGraphicsBackend::SetFillColor() { m_oFillColor = std::nullopt; }
667 void QtGraphicsBackend::SetFillColor(Color nColor) { m_oFillColor = nColor; }
669 void QtGraphicsBackend::SetXORMode(bool bSet, bool)
671 if (bSet)
672 m_eCompositionMode = QPainter::CompositionMode_Xor;
673 else
674 m_eCompositionMode = QPainter::CompositionMode_SourceOver;
677 void QtGraphicsBackend::SetROPLineColor(SalROPColor /*nROPColor*/) {}
679 void QtGraphicsBackend::SetROPFillColor(SalROPColor /*nROPColor*/) {}
681 bool QtGraphicsBackend::supportsOperation(OutDevSupportType eType) const
683 switch (eType)
685 case OutDevSupportType::TransparentRect:
686 return true;
687 default:
688 return false;
692 void QtGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
694 char* pForceDpi;
695 if ((pForceDpi = getenv("SAL_FORCEDPI")))
697 OString sForceDPI(pForceDpi);
698 rDPIX = rDPIY = sForceDPI.toInt32();
699 return;
702 if (!m_pFrame)
703 return;
705 QScreen* pScreen = m_pFrame->GetQWidget()->screen();
706 rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5;
707 rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5;
710 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */