prelim tdf#136472: remove implementation specific unit tests
[LibreOffice.git] / vcl / qt5 / QtGraphics_GDI.cxx
blob0f9faa022d0b514a58624117acf069b258fb62c3
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_aLineColor(0x00, 0x00, 0x00)
40 , m_aFillColor(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 bool 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);
165 return true;
168 void QtGraphicsBackend::ResetClipRegion()
170 if (m_pQImage)
171 m_aClipRegion = QRegion(m_pQImage->rect());
172 else
173 m_aClipRegion = QRegion();
174 if (!m_aClipPath.isEmpty())
176 QPainterPath aPath;
177 m_aClipPath.swap(aPath);
181 void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY)
183 QtPainter aPainter(*this);
184 aPainter.drawPoint(nX, nY);
185 aPainter.update(nX, nY, 1, 1);
188 void QtGraphicsBackend::drawPixel(tools::Long nX, tools::Long nY, Color nColor)
190 QtPainter aPainter(*this);
191 aPainter.setPen(toQColor(nColor));
192 aPainter.setPen(Qt::SolidLine);
193 aPainter.drawPoint(nX, nY);
194 aPainter.update(nX, nY, 1, 1);
197 void QtGraphicsBackend::drawLine(tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2)
199 QtPainter aPainter(*this);
200 aPainter.drawLine(nX1, nY1, nX2, nY2);
202 tools::Long tmp;
203 if (nX1 > nX2)
205 tmp = nX1;
206 nX1 = nX2;
207 nX2 = tmp;
209 if (nY1 > nY2)
211 tmp = nY1;
212 nY1 = nY2;
213 nY2 = tmp;
215 aPainter.update(nX1, nY1, nX2 - nX1 + 1, nY2 - nY1 + 1);
218 void QtGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
219 tools::Long nHeight)
221 if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
222 return;
224 QtPainter aPainter(*this, true);
225 if (SALCOLOR_NONE != m_aFillColor)
226 aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush());
227 if (SALCOLOR_NONE != m_aLineColor)
228 aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1);
229 aPainter.update(nX, nY, nWidth, nHeight);
232 void QtGraphicsBackend::drawPolyLine(sal_uInt32 nPoints, const Point* pPtAry)
234 if (0 == nPoints)
235 return;
237 QtPainter aPainter(*this);
238 QPoint* pPoints = new QPoint[nPoints];
239 QPoint aTopLeft(pPtAry->getX(), pPtAry->getY());
240 QPoint aBottomRight = aTopLeft;
241 for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry)
243 pPoints[i] = QPoint(pPtAry->getX(), pPtAry->getY());
244 if (pPtAry->getX() < aTopLeft.x())
245 aTopLeft.setX(pPtAry->getX());
246 if (pPtAry->getY() < aTopLeft.y())
247 aTopLeft.setY(pPtAry->getY());
248 if (pPtAry->getX() > aBottomRight.x())
249 aBottomRight.setX(pPtAry->getX());
250 if (pPtAry->getY() > aBottomRight.y())
251 aBottomRight.setY(pPtAry->getY());
253 aPainter.drawPolyline(pPoints, nPoints);
254 delete[] pPoints;
255 aPainter.update(QRect(aTopLeft, aBottomRight));
258 void QtGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPtAry)
260 QtPainter aPainter(*this, true);
261 QPolygon aPolygon(nPoints);
262 for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry)
263 aPolygon.setPoint(i, pPtAry->getX(), pPtAry->getY());
264 aPainter.drawPolygon(aPolygon);
265 aPainter.update(aPolygon.boundingRect());
268 void QtGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints,
269 const Point** ppPtAry)
271 // ignore invisible polygons
272 if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
273 return;
275 QPainterPath aPath;
276 for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++)
278 const sal_uInt32 nPoints = pPoints[nPoly];
279 if (nPoints > 1)
281 const Point* pPtAry = ppPtAry[nPoly];
282 aPath.moveTo(pPtAry->getX(), pPtAry->getY());
283 pPtAry++;
284 for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++)
285 aPath.lineTo(pPtAry->getX(), pPtAry->getY());
286 aPath.closeSubpath();
290 QtPainter aPainter(*this, true);
291 aPainter.drawPath(aPath);
292 aPainter.update(aPath.boundingRect());
295 bool QtGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
296 const basegfx::B2DPolyPolygon& rPolyPolygon,
297 double fTransparency)
299 // ignore invisible polygons
300 if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
301 return true;
302 if ((fTransparency >= 1.0) || (fTransparency < 0))
303 return true;
305 // Fallback: Transform to DeviceCoordinates
306 basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
307 aPolyPolygon.transform(rObjectToDevice);
309 QPainterPath aPath;
310 // ignore empty polygons
311 if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAlias(), m_aLineColor != SALCOLOR_NONE))
312 return true;
314 QtPainter aPainter(*this, true, 255 * (1.0 - fTransparency));
315 aPainter.drawPath(aPath);
316 aPainter.update(aPath.boundingRect());
317 return true;
320 bool QtGraphicsBackend::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
321 const PolyFlags* /*pFlgAry*/)
323 return false;
326 bool QtGraphicsBackend::drawPolygonBezier(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
327 const PolyFlags* /*pFlgAry*/)
329 return false;
332 bool QtGraphicsBackend::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/,
333 const Point* const* /*pPtAry*/,
334 const PolyFlags* const* /*pFlgAry*/)
336 return false;
339 bool QtGraphicsBackend::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice,
340 const basegfx::B2DPolygon& rPolyLine, double fTransparency,
341 double fLineWidth,
342 const std::vector<double>* pStroke, // MM01
343 basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap,
344 double fMiterMinimumAngle, bool bPixelSnapHairline)
346 if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
348 return true;
351 // MM01 check done for simple reasons
352 if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0)
354 return true;
357 // MM01 need to do line dashing as fallback stuff here now
358 const double fDotDashLength(
359 nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0);
360 const bool bStrokeUsed(0.0 != fDotDashLength);
361 assert(!bStrokeUsed || (bStrokeUsed && pStroke));
362 basegfx::B2DPolyPolygon aPolyPolygonLine;
364 if (bStrokeUsed)
366 // apply LineStyle
367 basegfx::utils::applyLineDashing(rPolyLine, // source
368 *pStroke, // pattern
369 &aPolyPolygonLine, // target for lines
370 nullptr, // target for gaps
371 fDotDashLength); // full length if available
373 else
375 // no line dashing, just copy
376 aPolyPolygonLine.append(rPolyLine);
379 // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline
380 aPolyPolygonLine.transform(rObjectToDevice);
381 if (bPixelSnapHairline)
383 aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine);
386 // tdf#124848 get correct LineWidth in discrete coordinates,
387 if (fLineWidth == 0) // hairline
388 fLineWidth = 1.0;
389 else // Adjust line width for object-to-device scale.
390 fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength();
392 // setup poly-polygon path
393 QPainterPath aPath;
395 // MM01 todo - I assume that this is OKAY to be done in one run for Qt,
396 // but this NEEDS to be checked/verified
397 for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++)
399 const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a));
400 AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAlias(), true);
403 QtPainter aPainter(*this, false, 255 * (1.0 - fTransparency));
405 // setup line attributes
406 QPen aPen = aPainter.pen();
407 aPen.setWidth(fLineWidth);
409 switch (eLineJoin)
411 case basegfx::B2DLineJoin::Bevel:
412 aPen.setJoinStyle(Qt::BevelJoin);
413 break;
414 case basegfx::B2DLineJoin::Round:
415 aPen.setJoinStyle(Qt::RoundJoin);
416 break;
417 case basegfx::B2DLineJoin::NONE:
418 case basegfx::B2DLineJoin::Miter:
419 aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0));
420 aPen.setJoinStyle(Qt::MiterJoin);
421 break;
424 switch (eLineCap)
426 default: // css::drawing::LineCap_BUTT:
427 aPen.setCapStyle(Qt::FlatCap);
428 break;
429 case css::drawing::LineCap_ROUND:
430 aPen.setCapStyle(Qt::RoundCap);
431 break;
432 case css::drawing::LineCap_SQUARE:
433 aPen.setCapStyle(Qt::SquareCap);
434 break;
437 aPainter.setPen(aPen);
438 aPainter.drawPath(aPath);
439 aPainter.update(aPath.boundingRect());
440 return true;
443 bool QtGraphicsBackend::drawGradient(const tools::PolyPolygon& /*rPolyPolygon*/,
444 const Gradient& /*rGradient*/)
446 return false;
449 bool QtGraphicsBackend::implDrawGradient(basegfx::B2DPolyPolygon const& /*rPolyPolygon*/,
450 SalGradient const& /*rGradient*/)
452 return false;
455 void QtGraphicsBackend::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage)
457 QtPainter aPainter(*this);
458 QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
459 QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight);
460 aPainter.drawImage(aDestRect, rImage, aSrcRect);
461 aPainter.update(aDestRect);
464 void QtGraphicsBackend::copyArea(tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX,
465 tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight,
466 bool /*bWindowInvalidate*/)
468 if (nDestX == nSrcX && nDestY == nSrcY)
469 return;
471 SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight);
473 QImage* pImage = m_pQImage;
474 QImage aImage = pImage->copy(aTR.mnSrcX, aTR.mnSrcY, aTR.mnSrcWidth, aTR.mnSrcHeight);
475 pImage = &aImage;
476 aTR.mnSrcX = 0;
477 aTR.mnSrcY = 0;
479 drawScaledImage(aTR, *pImage);
482 void QtGraphicsBackend::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics)
484 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
485 || rPosAry.mnDestHeight <= 0)
486 return;
488 QImage aImage, *pImage;
489 SalTwoRect aPosAry = rPosAry;
491 if (!pSrcGraphics)
493 pImage = m_pQImage;
494 aImage
495 = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight);
496 pImage = &aImage;
497 aPosAry.mnSrcX = 0;
498 aPosAry.mnSrcY = 0;
500 else
501 pImage = static_cast<QtGraphics*>(pSrcGraphics)->getQImage();
503 drawScaledImage(aPosAry, *pImage);
506 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
508 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
509 || rPosAry.mnDestHeight <= 0)
510 return;
512 const QImage* pImage = static_cast<const QtBitmap*>(&rSalBitmap)->GetQImage();
514 assert(pImage);
516 drawScaledImage(rPosAry, *pImage);
519 void QtGraphicsBackend::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
520 const SalBitmap& /*rTransparentBitmap*/)
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 void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/,
531 Color /*nMaskColor*/)
533 if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0
534 || rPosAry.mnDestHeight <= 0)
535 return;
537 assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth);
538 assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight);
541 std::shared_ptr<SalBitmap> QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY,
542 tools::Long nWidth, tools::Long nHeight)
544 return std::make_shared<QtBitmap>(m_pQImage->copy(nX, nY, nWidth, nHeight));
547 Color QtGraphicsBackend::getPixel(tools::Long nX, tools::Long nY)
549 return Color(ColorTransparency, m_pQImage->pixel(nX, nY));
552 void QtGraphicsBackend::invert(tools::Long nX, tools::Long nY, tools::Long nWidth,
553 tools::Long nHeight, SalInvert nFlags)
555 QtPainter aPainter(*this);
556 if (SalInvert::N50 & nFlags)
558 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
559 QBrush aBrush(Qt::white, Qt::Dense4Pattern);
560 aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush);
562 else
564 if (SalInvert::TrackFrame & nFlags)
566 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
567 QPen aPen(Qt::white);
568 aPen.setStyle(Qt::DotLine);
569 aPainter.setPen(aPen);
570 aPainter.drawRect(nX, nY, nWidth, nHeight);
572 else
574 aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination);
575 aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white);
578 aPainter.update(nX, nY, nWidth, nHeight);
581 void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
582 SalInvert /*nFlags*/)
586 bool QtGraphicsBackend::drawEPS(tools::Long /*nX*/, tools::Long /*nY*/, tools::Long /*nWidth*/,
587 tools::Long /*nHeight*/, void* /*pPtr*/, sal_uInt32 /*nSize*/)
589 return false;
592 bool QtGraphicsBackend::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/)
594 return false;
597 bool QtGraphicsBackend::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/,
598 const SalBitmap& /*rMaskBitmap*/,
599 const SalBitmap& /*rAlphaBitmap*/)
601 return false;
604 static bool getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap,
605 QImage& rAlphaImage)
607 if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1)
609 SAL_WARN("vcl.gdi", "unsupported alpha depth case: " << rAlphaBitmap.GetBitCount());
610 return false;
613 const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
614 const QImage* pAlpha = static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage();
615 rAlphaImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
617 if (rAlphaBitmap.GetBitCount() == 8)
619 for (int y = 0; y < rAlphaImage.height(); ++y)
621 uchar* image_line = rAlphaImage.scanLine(y);
622 const uchar* alpha_line = pAlpha->scanLine(y);
623 for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4)
624 image_line[3] = 255 - alpha_line[x];
627 else
629 for (int y = 0; y < rAlphaImage.height(); ++y)
631 uchar* image_line = rAlphaImage.scanLine(y);
632 const uchar* alpha_line = pAlpha->scanLine(y);
633 for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4)
635 if (x && !(x % 8))
636 ++alpha_line;
637 if (0 != (*alpha_line & (1 << (7 - x % 8))))
638 image_line[3] = 0;
643 return true;
646 bool QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap,
647 const SalBitmap& rAlphaBitmap)
649 QImage aImage;
650 if (!getAlphaImage(rSourceBitmap, rAlphaBitmap, aImage))
651 return false;
652 drawScaledImage(rPosAry, aImage);
653 return true;
656 bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
657 const basegfx::B2DPoint& rX,
658 const basegfx::B2DPoint& rY,
659 const SalBitmap& rSourceBitmap,
660 const SalBitmap* pAlphaBitmap, double fAlpha)
662 if (fAlpha != 1.0)
663 return false;
664 QImage aImage;
665 if (pAlphaBitmap && !getAlphaImage(rSourceBitmap, *pAlphaBitmap, aImage))
666 return false;
667 else
669 const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
670 aImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
673 QtPainter aPainter(*this);
674 const basegfx::B2DVector aXRel = rX - rNull;
675 const basegfx::B2DVector aYRel = rY - rNull;
676 aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(),
677 aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(),
678 rNull.getX(), rNull.getY()));
679 aPainter.drawImage(QPoint(0, 0), aImage);
680 aPainter.update(aImage.rect());
681 return true;
684 bool QtGraphicsBackend::hasFastDrawTransformedBitmap() const { return false; }
686 bool QtGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth,
687 tools::Long nHeight, sal_uInt8 nTransparency)
689 if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
690 return true;
691 assert(nTransparency <= 100);
692 if (nTransparency > 100)
693 nTransparency = 100;
694 QtPainter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100));
695 if (SALCOLOR_NONE != m_aFillColor)
696 aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush());
697 if (SALCOLOR_NONE != m_aLineColor)
698 aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1);
699 aPainter.update(nX, nY, nWidth, nHeight);
700 return true;
703 sal_uInt16 QtGraphicsBackend::GetBitCount() const { return getFormatBits(m_pQImage->format()); }
705 tools::Long QtGraphicsBackend::GetGraphicsWidth() const { return m_pQImage->width(); }
707 void QtGraphicsBackend::SetLineColor() { m_aLineColor = SALCOLOR_NONE; }
709 void QtGraphicsBackend::SetLineColor(Color nColor) { m_aLineColor = nColor; }
711 void QtGraphicsBackend::SetFillColor() { m_aFillColor = SALCOLOR_NONE; }
713 void QtGraphicsBackend::SetFillColor(Color nColor) { m_aFillColor = nColor; }
715 void QtGraphicsBackend::SetXORMode(bool bSet, bool)
717 if (bSet)
718 m_eCompositionMode = QPainter::CompositionMode_Xor;
719 else
720 m_eCompositionMode = QPainter::CompositionMode_SourceOver;
723 void QtGraphicsBackend::SetROPLineColor(SalROPColor /*nROPColor*/) {}
725 void QtGraphicsBackend::SetROPFillColor(SalROPColor /*nROPColor*/) {}
727 bool QtGraphicsBackend::supportsOperation(OutDevSupportType eType) const
729 switch (eType)
731 case OutDevSupportType::B2DDraw:
732 case OutDevSupportType::TransparentRect:
733 return true;
734 default:
735 return false;
739 void QtGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
741 char* pForceDpi;
742 if ((pForceDpi = getenv("SAL_FORCEDPI")))
744 OString sForceDPI(pForceDpi);
745 rDPIX = rDPIY = sForceDPI.toInt32();
746 return;
749 if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle())
750 return;
752 QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen();
753 rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5;
754 rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5;
757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */