From 4e86eeb9dd194d4ebf9c180fe2cb1dc1699601bf Mon Sep 17 00:00:00 2001 From: Markus Mohrhard Date: Thu, 23 Oct 2014 14:02:12 +0200 Subject: use Impl for windows backend Change-Id: Ie354aaf11644122754b69bc303c781297cacdc77 --- vcl/Library_vcl.mk | 1 + vcl/inc/win/salgdi.h | 19 +- vcl/win/source/gdi/gdiimpl.cxx | 2365 +++++++++++++++++++++++++++++++++ vcl/win/source/gdi/gdiimpl.hxx | 213 +++ vcl/win/source/gdi/salgdi.cxx | 945 +------------ vcl/win/source/gdi/salgdi2.cxx | 728 +--------- vcl/win/source/gdi/salgdi_gdiplus.cxx | 469 +------ 7 files changed, 2655 insertions(+), 2085 deletions(-) create mode 100644 vcl/win/source/gdi/gdiimpl.cxx create mode 100644 vcl/win/source/gdi/gdiimpl.hxx diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 52a224c93bac..3ed87133aa8c 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -624,6 +624,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/win/source/app/salinst \ vcl/win/source/app/salshl \ vcl/win/source/app/saltimer \ + vcl/win/source/gdi/gdiimpl \ vcl/win/source/gdi/salbmp \ vcl/win/source/gdi/salgdi \ vcl/win/source/gdi/salgdi2 \ diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 66c561830e49..4e53806e8751 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -40,6 +40,7 @@ class FontSelectPattern; class ImplWinFontEntry; class ImplFontAttrCache; class PhysicalFontCollection; +class SalGraphicsImpl; #define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000) #define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff) @@ -144,6 +145,8 @@ public: class WinSalGraphics : public SalGraphics { private: + boost::scoped_ptr mpImpl; + HDC mhLocalDC; // HDC public: @@ -152,20 +155,18 @@ public: public: HWND mhWnd; // Window-Handle, when Window-Graphics + + HWND gethWnd(); HFONT mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks const ImplWinFontData* mpWinFontData[ MAX_FALLBACK ]; // pointer to the most recent font face ImplWinFontEntry* mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance float mfFontScale[ MAX_FALLBACK ]; // allows metrics emulation of huge font sizes float mfCurrentFontScale; - HPEN mhPen; // Pen - HBRUSH mhBrush; // Brush HRGN mhRegion; // vcl::Region Handle HPEN mhDefPen; // DefaultPen HBRUSH mhDefBrush; // DefaultBrush HFONT mhDefFont; // DefaultFont HPALETTE mhDefPal; // DefaultPalette - COLORREF mnPenColor; // PenColor - COLORREF mnBrushColor; // BrushColor COLORREF mnTextColor; // TextColor RGNDATA* mpClipRgnData; // ClipRegion-Data RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data @@ -179,19 +180,10 @@ public: int mnPenWidth; // Linienbreite /// bitfield - bool mbStockPen : 1; // is Pen a stockpen - bool mbStockBrush : 1; // is Brush a stcokbrush - bool mbPen : 1; // is Pen (FALSE == NULL_PEN) - bool mbBrush : 1; // is Brush (FALSE == NULL_BRUSH) bool mbPrinter : 1; // is Printer bool mbVirDev : 1; // is VirDev bool mbWindow : 1; // is Window bool mbScreen : 1; // is Screen compatible - bool mbXORMode : 1; // _every_ output with RasterOp XOR - - // remember RGB values for SetLineColor/SetFillColor - SalColor maLineColor; - SalColor maFillColor; HFONT ImplDoSetFont( FontSelectPattern* i_pFont, float& o_rFontScale, HFONT& o_rOldFont ); @@ -270,7 +262,6 @@ protected: private: // local helpers - bool tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap); // get kernign pairs of the current font sal_uLong GetKernPairs(); diff --git a/vcl/win/source/gdi/gdiimpl.cxx b/vcl/win/source/gdi/gdiimpl.cxx new file mode 100644 index 000000000000..8ae2e759f0e8 --- /dev/null +++ b/vcl/win/source/gdi/gdiimpl.cxx @@ -0,0 +1,2365 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "gdiimpl.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "win/salbmp.h" +#include +#include +#include + +#include "outdata.hxx" +#include "win/salids.hrc" + +#if defined _MSC_VER +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif + +#if defined _MSC_VER +#pragma warning(push, 1) +#endif + +#ifdef __MINGW32__ +#ifdef GetObject +#undef GetObject +#endif +#endif + +#include +#include +#include + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include + +#define SAL_POLYPOLYCOUNT_STACKBUF 8 +#define SAL_POLYPOLYPOINTS_STACKBUF 64 + +#define DITHER_PAL_DELTA 51 +#define DITHER_PAL_STEPS 6 +#define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS) +#define DITHER_MAX_SYSCOLOR 16 +#define DITHER_EXTRA_COLORS 1 +#define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal]) + +namespace { + +// #100127# draw an array of points which might also contain bezier control points +void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ + if( nPoints ) + { + sal_uInt16 i; + // TODO: profile whether the following options are faster: + // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp. + // b) convert our flag array to window's and use PolyDraw + + MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL ); + ++pPtAry; ++pFlgAry; + + for( i=1; imnX, pPtAry->mnY ); + } + else if( nPoints - i > 2 ) + { + PolyBezierTo( hdc, reinterpret_cast(pPtAry), 3 ); + i += 2; pPtAry += 2; pFlgAry += 2; + } + } + } +} + +// #100127# Fill point and flag memory from array of points which +// might also contain bezier control points for the PolyDraw() GDI method +// Make sure pWinPointAry and pWinFlagAry are big enough +void ImplPreparePolyDraw( bool bCloseFigures, + sal_uLong nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const BYTE* const* pFlgAry, + POINT* pWinPointAry, + BYTE* pWinFlagAry ) +{ + sal_uLong nCurrPoly; + for( nCurrPoly=0; nCurrPoly( *pPtAry++ ); + const BYTE* pCurrFlag = *pFlgAry++; + const sal_uInt32 nCurrPoints = *pPoints++; + const bool bHaveFlagArray( pCurrFlag ); + sal_uLong nCurrPoint; + + if( nCurrPoints ) + { + // start figure + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_MOVETO; + ++pCurrFlag; + + for( nCurrPoint=1; nCurrPointpeRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue ) + return TRUE; + } + + // extra color? + if ( aImplExtraColor1.peRed == nRed && + aImplExtraColor1.peGreen == nGreen && + aImplExtraColor1.peBlue == nBlue ) + { + return TRUE; + } + + return FALSE; +} + +} + +WinSalGraphicsImpl::WinSalGraphicsImpl(WinSalGraphics& rParent): + mrParent(rParent), + mbXORMode(false), + mhPen(0), + mhBrush(0) +{ +} + +WinSalGraphicsImpl::~WinSalGraphicsImpl() +{ + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + +} + +void WinSalGraphicsImpl::freeResources() +{ +} + +bool WinSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uLong) +{ + return false; +} + +void WinSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) +{ + HDC hSrcDC; + DWORD nRop; + + if ( pSrcGraphics ) + hSrcDC = static_cast(pSrcGraphics)->getHDC(); + else + hSrcDC = mrParent.getHDC(); + + if ( mbXORMode ) + nRop = SRCINVERT; + else + nRop = SRCCOPY; + + if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) + { + BitBlt( mrParent.getHDC(), + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hSrcDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + nRop ); + } + else + { + int nOldStretchMode = SetStretchBltMode( mrParent.getHDC(), STRETCH_DELETESCANS ); + StretchBlt( mrParent.getHDC(), + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hSrcDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + nRop ); + SetStretchBltMode( mrParent.getHDC(), nOldStretchMode ); + } +} + +void ImplCalcOutSideRgn( const RECT& rSrcRect, + int nLeft, int nTop, int nRight, int nBottom, + HRGN& rhInvalidateRgn ) +{ + HRGN hTempRgn; + + // calculate area outside the visible region + if ( rSrcRect.left < nLeft ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.top < nTop ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.right > nRight ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.bottom > nBottom ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } +} + +void WinSalGraphicsImpl::copyArea( long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) +{ + bool bRestoreClipRgn = false; + HRGN hOldClipRgn = 0; + int nOldClipRgnType = ERROR; + HRGN hInvalidateRgn = 0; + + // do we have to invalidate also the overlapping regions? + if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mrParent.mbWindow ) + { + // compute and invalidate those parts that were either off-screen or covered by other windows + // while performing the above BitBlt + // those regions then have to be invalidated as they contain useless/wrong data + RECT aSrcRect; + RECT aClipRect; + RECT aTempRect; + RECT aTempRect2; + HRGN hTempRgn; + HWND hWnd; + + // restrict srcRect to this window (calc intersection) + aSrcRect.left = (int)nSrcX; + aSrcRect.top = (int)nSrcY; + aSrcRect.right = aSrcRect.left+(int)nSrcWidth; + aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight; + GetClientRect( mrParent.gethWnd(), &aClipRect ); + if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) ) + { + // transform srcRect to screen coordinates + POINT aPt; + aPt.x = 0; + aPt.y = 0; + ClientToScreen( mrParent.gethWnd(), &aPt ); + aSrcRect.left += aPt.x; + aSrcRect.top += aPt.y; + aSrcRect.right += aPt.x; + aSrcRect.bottom += aPt.y; + hInvalidateRgn = 0; + + // compute the parts that are off screen (ie invisible) + RECT theScreen; + ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account + ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn ); + + // calculate regions that are covered by other windows + HRGN hTempRgn2 = 0; + HWND hWndTopWindow = mrParent.gethWnd(); + // Find the TopLevel Window, because only Windows which are in + // in the foreground of our TopLevel window must be considered + if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ) + { + RECT aTempRect3 = aSrcRect; + do + { + hWndTopWindow = ::GetParent( hWndTopWindow ); + + // Test if the Parent clips our window + GetClientRect( hWndTopWindow, &aTempRect ); + POINT aPt2; + aPt2.x = 0; + aPt2.y = 0; + ClientToScreen( hWndTopWindow, &aPt2 ); + aTempRect.left += aPt2.x; + aTempRect.top += aPt2.y; + aTempRect.right += aPt2.x; + aTempRect.bottom += aPt2.y; + IntersectRect( &aTempRect3, &aTempRect3, &aTempRect ); + } + while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ); + + // If one or more Parents clip our window, than we must + // calculate the outside area + if ( !EqualRect( &aSrcRect, &aTempRect3 ) ) + { + ImplCalcOutSideRgn( aSrcRect, + aTempRect3.left, aTempRect3.top, + aTempRect3.right, aTempRect3.bottom, + hInvalidateRgn ); + } + } + // retrieve the top-most (z-order) child window + hWnd = GetWindow( GetDesktopWindow(), GW_CHILD ); + while ( hWnd ) + { + if ( hWnd == hWndTopWindow ) + break; + if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) ) + { + GetWindowRect( hWnd, &aTempRect ); + if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) ) + { + // hWnd covers part or all of aSrcRect + if ( !hInvalidateRgn ) + hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect ); + + // get full bounding box of hWnd + hTempRgn = CreateRectRgnIndirect( &aTempRect ); + + // get region of hWnd (the window may be shaped) + if ( !hTempRgn2 ) + hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 ); + int nRgnType = GetWindowRgn( hWnd, hTempRgn2 ); + if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) + { + // convert window region to screen coordinates + OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top ); + // and intersect with the window's bounding box + CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND ); + } + // finally compute that part of aSrcRect which is not covered by any parts of hWnd + CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + } + // retrieve the next window in the z-order, i.e. the window below hwnd + hWnd = GetWindow( hWnd, GW_HWNDNEXT ); + } + if ( hTempRgn2 ) + DeleteRegion( hTempRgn2 ); + if ( hInvalidateRgn ) + { + // hInvalidateRgn contains the fully visible parts of the original srcRect + hTempRgn = CreateRectRgnIndirect( &aSrcRect ); + // substract it from the original rect to get the occluded parts + int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + + if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) + { + // move the occluded parts to the destination pos + int nOffX = (int)(nDestX-nSrcX); + int nOffY = (int)(nDestY-nSrcY); + OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y ); + + // by excluding hInvalidateRgn from the system's clip region + // we will prevent bitblt from copying useless data + // epsecially now shadows from overlapping windows will appear (#i36344) + hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 ); + nOldClipRgnType = GetClipRgn( mrParent.getHDC(), hOldClipRgn ); + + bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate + ExtSelectClipRgn( mrParent.getHDC(), hInvalidateRgn, RGN_DIFF ); + } + } + } + } + + BitBlt( mrParent.getHDC(), + (int)nDestX, (int)nDestY, + (int)nSrcWidth, (int)nSrcHeight, + mrParent.getHDC(), + (int)nSrcX, (int)nSrcY, + SRCCOPY ); + + if( bRestoreClipRgn ) + { + // restore old clip region + if( nOldClipRgnType != ERROR ) + SelectClipRgn( mrParent.getHDC(), hOldClipRgn); + DeleteRegion( hOldClipRgn ); + + // invalidate regions that were not copied + bool bInvalidate = true; + + // Combine Invalidate vcl::Region with existing ClipRegion + HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 ); + if ( GetClipRgn( mrParent.getHDC(), hTempRgn ) == 1 ) + { + int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND ); + if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) ) + bInvalidate = false; + } + DeleteRegion( hTempRgn ); + + if ( bInvalidate ) + { + InvalidateRgn( mrParent.gethWnd(), hInvalidateRgn, TRUE ); + // here we only initiate an update if this is the MainThread, + // so that there is no deadlock when handling the Paint event, + // as the SolarMutex is already held by this Thread + SalData* pSalData = GetSalData(); + DWORD nCurThreadId = GetCurrentThreadId(); + if ( pSalData->mnAppThreadId == nCurThreadId ) + UpdateWindow( mrParent.gethWnd() ); + } + + DeleteRegion( hInvalidateRgn ); + } + +} + +namespace { + +void ImplDrawBitmap( HDC hDC, const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap, + bool bPrinter, int nDrawMode ) +{ + if( hDC ) + { + HGLOBAL hDrawDIB; + HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB(); + WinSalBitmap* pTmpSalBmp = NULL; + bool bPrintDDB = ( bPrinter && hDrawDDB ); + + if( bPrintDDB ) + { + pTmpSalBmp = new WinSalBitmap; + pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() ); + hDrawDIB = pTmpSalBmp->ImplGethDIB(); + } + else + hDrawDIB = rSalBitmap.ImplGethDIB(); + + if( hDrawDIB ) + { + PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); + PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; + PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + + rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); + const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); + + StretchDIBits( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + (int)rPosAry.mnSrcX, (int)(pBIH->biHeight - rPosAry.mnSrcHeight - rPosAry.mnSrcY), + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + pBits, pBI, DIB_RGB_COLORS, nDrawMode ); + + GlobalUnlock( hDrawDIB ); + SetStretchBltMode( hDC, nOldStretchMode ); + } + else if( hDrawDDB && !bPrintDDB ) + { + HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB ); + COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF); + COLORREF nOldTextColor = RGB(0,0,0); + bool bMono = ( rSalBitmap.GetBitCount() == 1 ); + + if( bMono ) + { + COLORREF nBkColor = RGB( 0xFF, 0xFF, 0xFF ); + COLORREF nTextColor = RGB( 0x00, 0x00, 0x00 ); + //fdo#33455 handle 1 bit depth pngs with palette entries + //to set fore/back colors + if (const BitmapBuffer* pBitmapBuffer = const_cast(rSalBitmap).AcquireBuffer(true)) + { + const BitmapPalette& rPalette = pBitmapBuffer->maPalette; + if (rPalette.GetEntryCount() == 2) + { + SalColor nCol; + nCol = ImplColorToSal(rPalette[0]); + nTextColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); + nCol = ImplColorToSal(rPalette[1]); + nBkColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); + } + } + nOldBkColor = SetBkColor( hDC, nBkColor ); + nOldTextColor = ::SetTextColor( hDC, nTextColor ); + } + + if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) + { + BitBlt( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hBmpDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + nDrawMode ); + } + else + { + const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); + + StretchBlt( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hBmpDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + nDrawMode ); + + SetStretchBltMode( hDC, nOldStretchMode ); + } + + if( bMono ) + { + SetBkColor( hDC, nOldBkColor ); + ::SetTextColor( hDC, nOldTextColor ); + } + + ImplReleaseCachedDC( CACHED_HDC_DRAW ); + } + + if( bPrintDDB ) + delete pTmpSalBmp; + } +} + +} + +void WinSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) +{ + bool bTryDirectPaint(!mrParent.mbPrinter && !mbXORMode); + + if(bTryDirectPaint) + { + // only paint direct when no scaling and no MapMode, else the + // more expensive conversions may be done for short-time Bitmap/BitmapEx + // used for buffering only + if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) + { + bTryDirectPaint = false; + } + } + + // try to draw using GdiPlus directly + if(bTryDirectPaint && tryDrawBitmapGdiPlus(rPosAry, rSalBitmap)) + { + return; + } + + // fall back old stuff + ImplDrawBitmap(mrParent.getHDC(), rPosAry, static_cast(rSalBitmap), + mrParent.mbPrinter, + mbXORMode ? SRCINVERT : SRCCOPY ); +} + +void WinSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + SalColor nTransparentColor ) +{ + DBG_ASSERT( !mrParent.mbPrinter, "No transparency print possible!" ); + + const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); + + WinSalBitmap* pMask = new WinSalBitmap; + const Point aPoint; + const Size aSize( rSalBitmap.GetSize() ); + HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL ); + HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap ); + const BYTE cRed = SALCOLOR_RED( nTransparentColor ); + const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor ); + const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor ); + + if( rSalBitmap.ImplGethDDB() ) + { + HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() ); + COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); + + BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); + + SetBkColor( hSrcDC, aOldCol ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + } + else + { + WinSalBitmap* pTmpSalBmp = new WinSalBitmap; + + if( pTmpSalBmp->Create( rSalBitmap, &mrParent ) ) + { + HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() ); + COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); + + BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); + + SetBkColor( hSrcDC, aOldCol ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + } + + delete pTmpSalBmp; + } + + ImplReleaseCachedDC( CACHED_HDC_1 ); + + // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE ) + if( pMask->Create( hMaskBitmap, FALSE, FALSE ) ) + drawBitmap( rPosAry, rSalBitmap, *pMask ); + + delete pMask; +} + +void WinSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + const SalBitmap& rSTransparentBitmap ) +{ + DBG_ASSERT( !mrParent.mbPrinter, "No transparency print possible!" ); + bool bTryDirectPaint(!mrParent.mbPrinter && !mbXORMode); + + if(bTryDirectPaint) + { + // only paint direct when no scaling and no MapMode, else the + // more expensive conversions may be done for short-time Bitmap/BitmapEx + // used for buffering only + if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) + { + bTryDirectPaint = false; + } + } + + // try to draw using GdiPlus directly + if(bTryDirectPaint && drawAlphaBitmap(rPosAry, rSSalBitmap, rSTransparentBitmap)) + { + return; + } + + const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); + const WinSalBitmap& rTransparentBitmap = static_cast(rSTransparentBitmap); + + SalTwoRect aPosAry = rPosAry; + int nDstX = (int)aPosAry.mnDestX; + int nDstY = (int)aPosAry.mnDestY; + int nDstWidth = (int)aPosAry.mnDestWidth; + int nDstHeight = (int)aPosAry.mnDestHeight; + HDC hDC = mrParent.getHDC(); + HBITMAP hMemBitmap = 0; + HBITMAP hMaskBitmap = 0; + + if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) ) + { + hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); + hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); + } + + HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap ); + HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap ); + + aPosAry.mnDestX = aPosAry.mnDestY = 0; + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY ); + + // WIN/WNT seems to have a minor problem mapping the correct color of the + // mask to the palette if we draw the DIB directly ==> draw DDB + if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 ) + { + WinSalBitmap aTmp; + + if( aTmp.Create( rTransparentBitmap, &mrParent ) ) + ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY ); + } + else + ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY ); + + // now MemDC contains background, MaskDC the transparency mask + + // #105055# Respect XOR mode + if( mbXORMode ) + { + ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); + // now MaskDC contains the bitmap area with black background + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT ); + // now MemDC contains background XORed bitmap area ontop + } + else + { + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND ); + // now MemDC contains background with masked-out bitmap area + ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); + // now MaskDC contains the bitmap area with black background + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT ); + // now MemDC contains background and bitmap merged together + } + // copy to output DC + BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY ); + + ImplReleaseCachedDC( CACHED_HDC_1 ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + + // hMemBitmap != 0 ==> hMaskBitmap != 0 + if( hMemBitmap ) + { + DeleteObject( hMemBitmap ); + DeleteObject( hMaskBitmap ); + } +} + +bool WinSalGraphicsImpl::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( mbPen || !mbBrush || mbXORMode ) + return false; // can only perform solid fills without XOR. + + HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 ); + SetPixel( hMemDC, (int)0, (int)0, mnBrushColor ); + + BLENDFUNCTION aFunc = { + AC_SRC_OVER, + 0, + sal::static_int_cast(255 - 255L*nTransparency/100), + 0 + }; + + // hMemDC contains a 1x1 bitmap of the right color - stretch-blit + // that to dest hdc + bool bRet = AlphaBlend( mrParent.getHDC(), nX, nY, nWidth, nHeight, + hMemDC, 0,0,1,1, + aFunc ) == TRUE; + + ImplReleaseCachedDC( CACHED_HDC_1 ); + + return bRet; +} + +void WinSalGraphicsImpl::drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + SalColor nMaskColor ) +{ + DBG_ASSERT( !mrParent.mbPrinter, "No transparency print possible!" ); + + const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); + + SalTwoRect aPosAry = rPosAry; + const BYTE cRed = SALCOLOR_RED( nMaskColor ); + const BYTE cGreen = SALCOLOR_GREEN( nMaskColor ); + const BYTE cBlue = SALCOLOR_BLUE( nMaskColor ); + HDC hDC = mrParent.getHDC(); + HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) ); + HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush ); + + // WIN/WNT seems to have a minor problem mapping the correct color of the + // mask to the palette if we draw the DIB directly ==> draw DDB + if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 ) + { + WinSalBitmap aTmp; + + if( aTmp.Create( rSalBitmap, &mrParent ) ) + ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL ); + } + else + ImplDrawBitmap( hDC, aPosAry, rSalBitmap, FALSE, 0x00B8074AUL ); + + SelectBrush( hDC, hOldBrush ); + DeleteBrush( hMaskBrush ); +} + +SalBitmap* WinSalGraphicsImpl::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + DBG_ASSERT( !mrParent.mbPrinter, "No ::GetBitmap() from printer possible!" ); + + WinSalBitmap* pSalBitmap = NULL; + + nDX = labs( nDX ); + nDY = labs( nDY ); + + HDC hDC = mrParent.getHDC(); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); + HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap ); + bool bRet; + + bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE; + ImplReleaseCachedDC( CACHED_HDC_1 ); + + if( bRet ) + { + pSalBitmap = new WinSalBitmap; + + if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) ) + { + delete pSalBitmap; + pSalBitmap = NULL; + } + } + else + { + // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers) + DeleteBitmap( hBmpBitmap ); + } + + return pSalBitmap; +} + +SalColor WinSalGraphicsImpl::getPixel( long nX, long nY ) +{ + COLORREF aWinCol = ::GetPixel( mrParent.getHDC(), (int) nX, (int) nY ); + + if ( CLR_INVALID == aWinCol ) + return MAKE_SALCOLOR( 0, 0, 0 ); + else + return MAKE_SALCOLOR( GetRValue( aWinCol ), + GetGValue( aWinCol ), + GetBValue( aWinCol ) ); +} + +void WinSalGraphicsImpl::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) +{ + if ( nFlags & SAL_INVERT_TRACKFRAME ) + { + HPEN hDotPen = CreatePen( PS_DOT, 0, 0 ); + HPEN hOldPen = SelectPen( mrParent.getHDC(), hDotPen ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), GetStockBrush( NULL_BRUSH ) ); + int nOldROP = SetROP2( mrParent.getHDC(), R2_NOT ); + + WIN_Rectangle( mrParent.getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); + + SetROP2( mrParent.getHDC(), nOldROP ); + SelectPen( mrParent.getHDC(), hOldPen ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeletePen( hDotPen ); + } + else if ( nFlags & SAL_INVERT_50 ) + { + SalData* pSalData = GetSalData(); + if ( !pSalData->mh50Brush ) + { + if ( !pSalData->mh50Bmp ) + pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); + pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); + } + + COLORREF nOldTextColor = ::SetTextColor( mrParent.getHDC(), 0 ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), pSalData->mh50Brush ); + PatBlt( mrParent.getHDC(), nX, nY, nWidth, nHeight, PATINVERT ); + ::SetTextColor( mrParent.getHDC(), nOldTextColor ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + } + else + { + RECT aRect; + aRect.left = (int)nX; + aRect.top = (int)nY; + aRect.right = (int)nX+nWidth; + aRect.bottom = (int)nY+nHeight; + ::InvertRect( mrParent.getHDC(), &aRect ); + } +} + +void WinSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) +{ + HPEN hPen; + HPEN hOldPen; + HBRUSH hBrush; + HBRUSH hOldBrush = 0; + COLORREF nOldTextColor RGB(0,0,0); + int nOldROP = SetROP2( mrParent.getHDC(), R2_NOT ); + + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + hPen = CreatePen( PS_DOT, 0, 0 ); + else + { + + if ( nSalFlags & SAL_INVERT_50 ) + { + SalData* pSalData = GetSalData(); + if ( !pSalData->mh50Brush ) + { + if ( !pSalData->mh50Bmp ) + pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); + pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); + } + + hBrush = pSalData->mh50Brush; + } + else + hBrush = GetStockBrush( BLACK_BRUSH ); + + hPen = GetStockPen( NULL_PEN ); + nOldTextColor = ::SetTextColor( mrParent.getHDC(), 0 ); + hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + } + hOldPen = SelectPen( mrParent.getHDC(), hPen ); + + POINT* pWinPtAry; + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" ); + + pWinPtAry = (POINT*)pPtAry; + // for Windows 95 and its maximum number of points + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + { + if ( !Polyline( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + Polyline( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + } + else + { + if ( !WIN_Polygon( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + WIN_Polygon( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + } + + SetROP2( mrParent.getHDC(), nOldROP ); + SelectPen( mrParent.getHDC(), hOldPen ); + + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + DeletePen( hPen ); + else + { + ::SetTextColor( mrParent.getHDC(), nOldTextColor ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + } +} + +sal_uInt16 WinSalGraphicsImpl::GetBitCount() const +{ + return (sal_uInt16)GetDeviceCaps( mrParent.getHDC(), BITSPIXEL ); +} + +long WinSalGraphicsImpl::GetGraphicsWidth() const +{ + if( mrParent.gethWnd() && IsWindow( mrParent.gethWnd() ) ) + { + WinSalFrame* pFrame = GetWindowPtr( mrParent.gethWnd() ); + if( pFrame ) + { + if( pFrame->maGeometry.nWidth ) + return pFrame->maGeometry.nWidth; + else + { + // TODO: perhaps not needed, maGeometry should always be up-to-date + RECT aRect; + GetClientRect( mrParent.gethWnd(), &aRect ); + return aRect.right; + } + } + } + + return 0; +} + +void WinSalGraphicsImpl::ResetClipRegion() +{ + if ( mrParent.mhRegion ) + { + DeleteRegion( mrParent.mhRegion ); + mrParent.mhRegion = 0; + } + + SelectClipRgn( mrParent.getHDC(), 0 ); +} + +bool WinSalGraphicsImpl::setClipRegion( const vcl::Region& i_rClip ) +{ + if ( mrParent.mhRegion ) + { + DeleteRegion( mrParent.mhRegion ); + mrParent.mhRegion = 0; + } + + bool bUsePolygon(i_rClip.HasPolyPolygonOrB2DPolyPolygon()); + static bool bTryToAvoidPolygon(true); + + // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve + // and only contains horizontal/vertical edges. In that case, use the fallback + // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do + // the correct polygon-to-RegionBand transformation. + // Background is that when using the same Rectangle as rectangle or as Polygon + // clip region will lead to different results; the polygon-based one will be + // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This + // again is because of the polygon-nature and it's classic handling when filling. + // This also means that all cases which use a 'true' polygon-based incarnation of + // a vcl::Region should know what they do - it may lead to repaint errors. + if(bUsePolygon && bTryToAvoidPolygon) + { + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); + + if(!aPolyPolygon.areControlPointsUsed()) + { + if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon)) + { + bUsePolygon = false; + } + } + } + + if(bUsePolygon) + { + // #i122149# check the comment above to know that this may lead to potential repaint + // problems. It may be solved (if needed) by scaling the polygon by one in X + // and Y. Currently the workaround to only use it if really unavoidable will + // solve most cases. When someone is really using polygon-based Regions he + // should know what he is doing. + // Added code to do that scaling to check if it works, testing it. + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); + const sal_uInt32 nCount(aPolyPolygon.count()); + + if( nCount ) + { + std::vector< POINT > aPolyPoints; + aPolyPoints.reserve( 1024 ); + std::vector< INT > aPolyCounts( nCount, 0 ); + basegfx::B2DHomMatrix aExpand; + static bool bExpandByOneInXandY(true); + + if(bExpandByOneInXandY) + { + const basegfx::B2DRange aRangeS(aPolyPolygon.getB2DRange()); + const basegfx::B2DRange aRangeT(aRangeS.getMinimum(), aRangeS.getMaximum() + basegfx::B2DTuple(1.0, 1.0)); + aExpand = basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS, aRangeT)); + } + + for(sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DPolygon aPoly( + basegfx::tools::adaptiveSubdivideByDistance( + aPolyPolygon.getB2DPolygon(a), + 1)); + const sal_uInt32 nPoints(aPoly.count()); + aPolyCounts[a] = nPoints; + + for( sal_uInt32 b = 0; b < nPoints; b++ ) + { + basegfx::B2DPoint aPt(aPoly.getB2DPoint(b)); + + if(bExpandByOneInXandY) + { + aPt = aExpand * aPt; + } + + POINT aPOINT; + // #i122149# do correct rounding + aPOINT.x = basegfx::fround(aPt.getX()); + aPOINT.y = basegfx::fround(aPt.getY()); + aPolyPoints.push_back( aPOINT ); + } + } + + mrParent.mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE ); + } + } + else + { + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + sal_uLong nRectBufSize = sizeof(RECT)*aRectangles.size(); + if ( aRectangles.size() < SAL_CLIPRECT_COUNT ) + { + if ( !mrParent.mpStdClipRgnData ) + mrParent.mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; + mrParent.mpClipRgnData = mrParent.mpStdClipRgnData; + } + else + mrParent.mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; + mrParent.mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); + mrParent.mpClipRgnData->rdh.iType = RDH_RECTANGLES; + mrParent.mpClipRgnData->rdh.nCount = aRectangles.size(); + mrParent.mpClipRgnData->rdh.nRgnSize = nRectBufSize; + RECT* pBoundRect = &(mrParent.mpClipRgnData->rdh.rcBound); + SetRectEmpty( pBoundRect ); + RECT* pNextClipRect = (RECT*)(&(mrParent.mpClipRgnData->Buffer)); + bool bFirstClipRect = true; + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) + { + const long nW(aRectIter->GetWidth()); + const long nH(aRectIter->GetHeight()); + + if(nW && nH) + { + const long nRight(aRectIter->Left() + nW); + const long nBottom(aRectIter->Top() + nH); + + if(bFirstClipRect) + { + pBoundRect->left = aRectIter->Left(); + pBoundRect->top = aRectIter->Top(); + pBoundRect->right = nRight; + pBoundRect->bottom = nBottom; + bFirstClipRect = false; + } + else + { + if(aRectIter->Left() < pBoundRect->left) + { + pBoundRect->left = (int)aRectIter->Left(); + } + + if(aRectIter->Top() < pBoundRect->top) + { + pBoundRect->top = (int)aRectIter->Top(); + } + + if(nRight > pBoundRect->right) + { + pBoundRect->right = (int)nRight; + } + + if(nBottom > pBoundRect->bottom) + { + pBoundRect->bottom = (int)nBottom; + } + } + + pNextClipRect->left = (int)aRectIter->Left(); + pNextClipRect->top = (int)aRectIter->Top(); + pNextClipRect->right = (int)nRight; + pNextClipRect->bottom = (int)nBottom; + pNextClipRect++; + } + else + { + mrParent.mpClipRgnData->rdh.nCount--; + mrParent.mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); + } + } + + // create clip region from ClipRgnData + if(0 == mrParent.mpClipRgnData->rdh.nCount) + { + // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given + // that contains no polygons or only empty ones (no width/height). This is + // perfectly fine and we are done, except setting it (see end of method) + } + else if(1 == mrParent.mpClipRgnData->rdh.nCount) + { + RECT* pRect = &(mrParent.mpClipRgnData->rdh.rcBound); + mrParent.mhRegion = CreateRectRgn( pRect->left, pRect->top, + pRect->right, pRect->bottom ); + } + else if(mrParent.mpClipRgnData->rdh.nCount > 1) + { + sal_uLong nSize = mrParent.mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); + mrParent.mhRegion = ExtCreateRegion( NULL, nSize, mrParent.mpClipRgnData ); + + // if ExtCreateRegion(...) is not supported + if( !mrParent.mhRegion ) + { + RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mrParent.mpClipRgnData; + + if( pHeader->nCount ) + { + RECT* pRect = (RECT*) mrParent.mpClipRgnData->Buffer; + mrParent.mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); + pRect++; + + for( sal_uLong n = 1; n < pHeader->nCount; n++, pRect++ ) + { + HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); + CombineRgn( mrParent.mhRegion, mrParent.mhRegion, hRgn, RGN_OR ); + DeleteRegion( hRgn ); + } + } + } + + if ( mrParent.mpClipRgnData != mrParent.mpStdClipRgnData ) + delete [] mrParent.mpClipRgnData; + } + } + + if( mrParent.mhRegion ) + { + SelectClipRgn( mrParent.getHDC(), mrParent.mhRegion ); + + // debug code if you weant to check range of the newly applied ClipRegion + //RECT aBound; + //const int aRegionType = GetRgnBox(mrParent.mhRegion, &aBound); + + //bool bBla = true; + } + else + { + // #i123585# See above, this is a valid case, execute it + SelectClipRgn( mrParent.getHDC(), 0 ); + } + + // #i123585# retval no longer dependent of mrParent.mhRegion, see TaskId comments above + return true; +} + +void WinSalGraphicsImpl::SetLineColor() +{ + // create and select new pen + HPEN hNewPen = GetStockPen( NULL_PEN ); + HPEN hOldPen = SelectPen( mrParent.getHDC(), hNewPen ); + + // destroy or save old pen + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + else + mrParent.mhDefPen = hOldPen; + + // set new data + mhPen = hNewPen; + mbPen = FALSE; + mbStockPen = TRUE; +} + +void WinSalGraphicsImpl::SetLineColor( SalColor nSalColor ) +{ + maLineColor = nSalColor; + COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + HPEN hNewPen = 0; + bool bStockPen = FALSE; + + // search for stock pen (only screen, because printer have problems, + // when we use stock objects) + if ( !mrParent.mbPrinter ) + { + SalData* pSalData = GetSalData(); + for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ ) + { + if ( nPenColor == pSalData->maStockPenColorAry[i] ) + { + hNewPen = pSalData->mhStockPenAry[i]; + bStockPen = TRUE; + break; + } + } + } + + // create new pen + if ( !hNewPen ) + { + if ( !mrParent.mbPrinter ) + { + if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) ) + nPenColor = PALRGB_TO_RGB( nPenColor ); + } + + hNewPen = CreatePen( PS_SOLID, mrParent.mnPenWidth, nPenColor ); + bStockPen = FALSE; + } + + // select new pen + HPEN hOldPen = SelectPen( mrParent.getHDC(), hNewPen ); + + // destroy or save old pen + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + else + mrParent.mhDefPen = hOldPen; + + // set new data + mnPenColor = nPenColor; + mhPen = hNewPen; + mbPen = TRUE; + mbStockPen = bStockPen; +} + +void WinSalGraphicsImpl::SetFillColor() +{ + // create and select new brush + HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hNewBrush ); + + // destroy or save old brush + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + else + mrParent.mhDefBrush = hOldBrush; + + // set new data + mhBrush = hNewBrush; + mbBrush = FALSE; + mbStockBrush = TRUE; +} + +void WinSalGraphicsImpl::SetFillColor( SalColor nSalColor ) +{ + maFillColor = nSalColor; + SalData* pSalData = GetSalData(); + BYTE nRed = SALCOLOR_RED( nSalColor ); + BYTE nGreen = SALCOLOR_GREEN( nSalColor ); + BYTE nBlue = SALCOLOR_BLUE( nSalColor ); + COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue ); + HBRUSH hNewBrush = 0; + bool bStockBrush = FALSE; + + // search for stock brush (only screen, because printer have problems, + // when we use stock objects) + if ( !mrParent.mbPrinter ) + { + for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ ) + { + if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] ) + { + hNewBrush = pSalData->mhStockBrushAry[i]; + bStockBrush = TRUE; + break; + } + } + } + + // create new brush + if ( !hNewBrush ) + { + if ( mrParent.mbPrinter || !pSalData->mhDitherDIB ) + hNewBrush = CreateSolidBrush( nBrushColor ); + else + { + if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount ) + { + BYTE* pTmp = pSalData->mpDitherDIBData; + long* pDitherDiff = pSalData->mpDitherDiff; + BYTE* pDitherLow = pSalData->mpDitherLow; + BYTE* pDitherHigh = pSalData->mpDitherHigh; + + for( long nY = 0L; nY < 8L; nY++ ) + { + for( long nX = 0L; nX < 8L; nX++ ) + { + const long nThres = aOrdDither16Bit[ nY ][ nX ]; + *pTmp++ = DMAP( nBlue, nThres ); + *pTmp++ = DMAP( nGreen, nThres ); + *pTmp++ = DMAP( nRed, nThres ); + } + } + + hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS ); + } + else if ( ImplIsSysColorEntry( nSalColor ) ) + { + nBrushColor = PALRGB_TO_RGB( nBrushColor ); + hNewBrush = CreateSolidBrush( nBrushColor ); + } + else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) ) + hNewBrush = CreateSolidBrush( nBrushColor ); + else + { + BYTE* pTmp = pSalData->mpDitherDIBData; + long* pDitherDiff = pSalData->mpDitherDiff; + BYTE* pDitherLow = pSalData->mpDitherLow; + BYTE* pDitherHigh = pSalData->mpDitherHigh; + + for ( long nY = 0L; nY < 8L; nY++ ) + { + for ( long nX = 0L; nX < 8L; nX++ ) + { + const long nThres = aOrdDither8Bit[ nY ][ nX ]; + *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36; + pTmp++; + } + } + + hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS ); + } + } + + bStockBrush = FALSE; + } + + // select new brush + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hNewBrush ); + + // destroy or save old brush + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + else + mrParent.mhDefBrush = hOldBrush; + + // set new data + mnBrushColor = nBrushColor; + mhBrush = hNewBrush; + mbBrush = TRUE; + mbStockBrush = bStockBrush; +} + +void WinSalGraphicsImpl::SetXORMode( bool bSet, bool ) +{ + mbXORMode = bSet; + ::SetROP2( mrParent.getHDC(), bSet ? R2_XORPEN : R2_COPYPEN ); +} + +void WinSalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor ) +{ + SetLineColor( ImplGetROPSalColor( nROPColor ) ); +} + +void WinSalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor ) +{ + SetFillColor( ImplGetROPSalColor( nROPColor ) ); +} + +void WinSalGraphicsImpl::drawPixel( long nX, long nY ) +{ + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)nX, (int)nY, mnPenColor ); +} + +void WinSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + + if ( !mrParent.mbPrinter && + GetSalData()->mhDitherPal && + ImplIsSysColorEntry( nSalColor ) ) + nCol = PALRGB_TO_RGB( nCol ); + + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( nCol ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + ::SetPixel( mrParent.getHDC(), (int)nX, (int)nY, nCol ); +} + +void WinSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + MoveToEx( mrParent.getHDC(), (int)nX1, (int)nY1, NULL ); + + // we must paint the endpoint + int bPaintEnd = TRUE; + if ( nX1 == nX2 ) + { + bPaintEnd = FALSE; + if ( nY1 <= nY2 ) + nY2++; + else + nY2--; + } + if ( nY1 == nY2 ) + { + bPaintEnd = FALSE; + if ( nX1 <= nX2 ) + nX2++; + else + nX2--; + } + + LineTo( mrParent.getHDC(), (int)nX2, (int)nY2 ); + + if ( bPaintEnd && !mrParent.mbPrinter ) + { + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)nX2, (int)nY2, mnPenColor ); + } +} + +void WinSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + if ( !mbPen ) + { + if ( !mrParent.mbPrinter ) + { + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight, + mbXORMode ? PATINVERT : PATCOPY ); + } + else + { + RECT aWinRect; + aWinRect.left = nX; + aWinRect.top = nY; + aWinRect.right = nX+nWidth; + aWinRect.bottom = nY+nHeight; + ::FillRect( mrParent.getHDC(), &aWinRect, mhBrush ); + } + } + else + WIN_Rectangle( mrParent.getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); +} + +void WinSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" ); + + POINT* pWinPtAry = (POINT*)pPtAry; + + // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN) + // we must paint the endpoint for last line + BOOL bPaintEnd = TRUE; + if ( pWinPtAry[nPoints-2].x == pWinPtAry[nPoints-1].x ) + { + bPaintEnd = FALSE; + if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y ) + pWinPtAry[nPoints-1].y++; + else + pWinPtAry[nPoints-1].y--; + } + if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y ) + { + bPaintEnd = FALSE; + if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x ) + pWinPtAry[nPoints-1].x++; + else + pWinPtAry[nPoints-1].x--; + } + + // for Windows 95 and its maximum number of points + if ( !Polyline( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + Polyline( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + + if ( bPaintEnd && !mrParent.mbPrinter ) + { + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), mnPenColor ); + } +} + +void WinSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolygon(): POINT != SalPoint" ); + + POINT* pWinPtAry = (POINT*)pPtAry; + // for Windows 95 and its maximum number of points + if ( !WIN_Polygon( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + WIN_Polygon( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); +} + +void WinSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry ) +{ + UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF]; + UINT* pWinPointAry; + UINT nPolyPolyPoints = 0; + UINT nPoints; + UINT i; + + if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF ) + pWinPointAry = aWinPointAry; + else + pWinPointAry = new UINT[nPoly]; + + for ( i = 0; i < (UINT)nPoly; i++ ) + { + nPoints = (UINT)pPoints[i]+1; + pWinPointAry[i] = nPoints; + nPolyPolyPoints += nPoints; + } + + POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF]; + POINT* pWinPointAryAry; + if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF ) + pWinPointAryAry = aWinPointAryAry; + else + pWinPointAryAry = new POINT[nPolyPolyPoints]; + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyPolygon(): POINT != SalPoint" ); + const SalPoint* pPolyAry; + UINT n = 0; + for ( i = 0; i < (UINT)nPoly; i++ ) + { + nPoints = pWinPointAry[i]; + pPolyAry = pPtAry[i]; + memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) ); + pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n]; + n += nPoints; + } + + if ( !WIN_PolyPolygon( mrParent.getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) && + (nPolyPolyPoints > MAX_64KSALPOINTS) ) + { + nPolyPolyPoints = 0; + nPoly = 0; + do + { + nPolyPolyPoints += pWinPointAry[(UINT)nPoly]; + nPoly++; + } + while ( nPolyPolyPoints < MAX_64KSALPOINTS ); + nPoly--; + if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS ) + pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS; + if ( nPoly == 1 ) + WIN_Polygon( mrParent.getHDC(), pWinPointAryAry, *pWinPointAry ); + else + WIN_PolyPolygon( mrParent.getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly ); + } + + if ( pWinPointAry != aWinPointAry ) + delete [] pWinPointAry; + if ( pWinPointAryAry != aWinPointAryAry ) + delete [] pWinPointAryAry; +} + +#define SAL_POLY_STACKBUF 32 +#define USE_GDI_BEZIERS + +bool WinSalGraphicsImpl::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLineBezier(): POINT != SalPoint" ); + + ImplRenderPath( mrParent.getHDC(), nPoints, pPtAry, pFlgAry ); + + return true; +#else + return false; +#endif +} + +bool WinSalGraphicsImpl::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolygonBezier(): POINT != SalPoint" ); + + POINT aStackAry1[SAL_POLY_STACKBUF]; + BYTE aStackAry2[SAL_POLY_STACKBUF]; + POINT* pWinPointAry; + BYTE* pWinFlagAry; + if( nPoints > SAL_POLY_STACKBUF ) + { + pWinPointAry = new POINT[ nPoints ]; + pWinFlagAry = new BYTE[ nPoints ]; + } + else + { + pWinPointAry = aStackAry1; + pWinFlagAry = aStackAry2; + } + + sal_uInt32 nPoints_i32(nPoints); + ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry); + + bool bRet( false ); + + if( BeginPath( mrParent.getHDC() ) ) + { + PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nPoints); + + if( EndPath( mrParent.getHDC() ) ) + { + if( StrokeAndFillPath( mrParent.getHDC() ) ) + bRet = true; + } + } + + if( pWinPointAry != aStackAry1 ) + { + delete [] pWinPointAry; + delete [] pWinFlagAry; + } + + return bRet; +#else + return false; +#endif +} + +bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyPolygonBezier(): POINT != SalPoint" ); + + sal_uLong nCurrPoly, nTotalPoints; + const sal_uInt32* pCurrPoints = pPoints; + for( nCurrPoly=0, nTotalPoints=0; nCurrPoly SAL_POLY_STACKBUF ) + { + pWinPointAry = new POINT[ nTotalPoints ]; + pWinFlagAry = new BYTE[ nTotalPoints ]; + } + else + { + pWinPointAry = aStackAry1; + pWinFlagAry = aStackAry2; + } + + ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry); + + bool bRet( false ); + + if( BeginPath( mrParent.getHDC() ) ) + { + PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints); + + if( EndPath( mrParent.getHDC() ) ) + { + if( StrokeAndFillPath( mrParent.getHDC() ) ) + bRet = true; + } + } + + if( pWinPointAry != aStackAry1 ) + { + delete [] pWinPointAry; + delete [] pWinFlagAry; + } + + return bRet; +#else + return false; +#endif +} + +void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) +{ + sal_uInt32 nCount(rPolygon.count()); + + if(nCount) + { + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nCount); + const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + + if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) + { + const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); + + Gdiplus::DllExports::GdipAddPathBezier(pPath, + aCurr.getX(), aCurr.getY(), + aCa.getX(), aCa.getY(), + aCb.getX(), aCb.getY(), + aNext.getX(), aNext.getY()); + } + else + { + Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); + } + + if(a + 1 < nEdgeCount) + { + aCurr = aNext; + + if(bNoLineJoin) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); + } + } + } + } +} + +void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) +{ + sal_uInt32 nCount(rPolygon.count()); + + if(nCount) + { + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nCount); + const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + + if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) + { + const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); + + Gdiplus::DllExports::GdipAddPathBezier( + pPath, + aCurr.getX(), aCurr.getY(), + aCa.getX(), aCa.getY(), + aCb.getX(), aCb.getY(), + aNext.getX(), aNext.getY()); + } + else + { + Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); + } + + if(a + 1 < nEdgeCount) + { + aCurr = aNext; + + if(bNoLineJoin) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); + } + } + } + } +} + +bool WinSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) +{ + const sal_uInt32 nCount(rPolyPolygon.count()); + + if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) + { + Gdiplus::GpGraphics *pGraphics = NULL; + Gdiplus::DllExports::GdipCreateFromHDC(mrParent.getHDC(), &pGraphics); + const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0)); + Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor)); + Gdiplus::GpSolidFill *pTestBrush; + Gdiplus::DllExports::GdipCreateSolidFill(aTestColor.GetValue(), &pTestBrush); + Gdiplus::GpPath *pPath = NULL; + Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); + + for(sal_uInt32 a(0); a < nCount; a++) + { + if(0 != a) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); // #i101491# not needed for first run + } + + impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false); + Gdiplus::DllExports::GdipClosePathFigure(pPath); + } + + if(mrParent.getAntiAliasB2DDraw()) + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); + } + else + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); + } + + if(mrParent.mbPrinter) + { + // #i121591# + // Normally GdiPlus should not be used for printing at all since printers cannot + // print transparent filled polygon geometry and normally this does not happen + // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation + // and no transparent parts should remain for printing. But this can be overridden + // by the user and thus happens. This call can only come (currently) from + // OutputDevice::DrawTransparent, see comments there with the same TaskID. + // If it is used, the mapping for the printer is wrong and needs to be corrected. I + // checked that there is *no* transformation set and estimated that a stable factor + // dependent of the printer's DPI is used. Create and set a transformation here to + // correct this. + Gdiplus::REAL aDpiX; + Gdiplus::DllExports::GdipGetDpiX(pGraphics, &aDpiX); + Gdiplus::REAL aDpiY; + Gdiplus::DllExports::GdipGetDpiY(pGraphics, &aDpiY); + + Gdiplus::DllExports::GdipResetWorldTransform(pGraphics); + Gdiplus::DllExports::GdipScaleWorldTransform(pGraphics, Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend); + } + + Gdiplus::DllExports::GdipFillPath(pGraphics, pTestBrush, pPath); + + Gdiplus::DllExports::GdipDeletePath(pPath); + Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); + } + + return true; +} + +bool WinSalGraphicsImpl::drawPolyLine( + const basegfx::B2DPolygon& rPolygon, + double fTransparency, + const basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin eLineJoin, + com::sun::star::drawing::LineCap eLineCap) +{ + const sal_uInt32 nCount(rPolygon.count()); + + if(mbPen && nCount) + { + Gdiplus::GpGraphics *pGraphics = NULL; + Gdiplus::DllExports::GdipCreateFromHDC(mrParent.getHDC(), &pGraphics); + const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) ); + Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); + Gdiplus::GpPen *pTestPen = NULL; + Gdiplus::DllExports::GdipCreatePen1(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX()), Gdiplus::UnitWorld, &pTestPen); + Gdiplus::GpPath *pPath; + Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); + bool bNoLineJoin(false); + + switch(eLineJoin) + { + default : // basegfx::B2DLINEJOIN_NONE : + { + if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) + { + bNoLineJoin = true; + } + break; + } + case basegfx::B2DLINEJOIN_BEVEL : + { + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinBevel); + break; + } + case basegfx::B2DLINEJOIN_MIDDLE : + case basegfx::B2DLINEJOIN_MITER : + { + const Gdiplus::REAL aMiterLimit(15.0); + Gdiplus::DllExports::GdipSetPenMiterLimit(pTestPen, aMiterLimit); + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinMiter); + break; + } + case basegfx::B2DLINEJOIN_ROUND : + { + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinRound); + break; + } + } + + switch(eLineCap) + { + default: /*com::sun::star::drawing::LineCap_BUTT*/ + { + // nothing to do + break; + } + case com::sun::star::drawing::LineCap_ROUND: + { + Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapRound); + Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapRound); + break; + } + case com::sun::star::drawing::LineCap_SQUARE: + { + Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapSquare); + Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapSquare); + break; + } + } + + if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) + { + impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath, rPolygon, bNoLineJoin); + } + else + { + impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin); + } + + if(rPolygon.isClosed() && !bNoLineJoin) + { + // #i101491# needed to create the correct line joins + Gdiplus::DllExports::GdipClosePathFigure(pPath); + } + + if(mrParent.getAntiAliasB2DDraw()) + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); + } + else + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); + } + + Gdiplus::DllExports::GdipDrawPath(pGraphics, pTestPen, pPath); + + Gdiplus::DllExports::GdipDeletePath(pPath); + Gdiplus::DllExports::GdipDeletePen(pTestPen); + Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); + } + + return true; +} + +void paintToGdiPlus( + Gdiplus::Graphics& rGraphics, + const SalTwoRect& rTR, + Gdiplus::Bitmap& rBitmap) +{ + // only parts of source are used + Gdiplus::PointF aDestPoints[3]; + Gdiplus::ImageAttributes aAttributes; + + // define target region as paralellogram + aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); + aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); + aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); + aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); + aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); + aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); + + aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); + + rGraphics.DrawImage( + &rBitmap, + aDestPoints, + 3, + Gdiplus::REAL(rTR.mnSrcX), + Gdiplus::REAL(rTR.mnSrcY), + Gdiplus::REAL(rTR.mnSrcWidth), + Gdiplus::REAL(rTR.mnSrcHeight), + Gdiplus::UnitPixel, + &aAttributes, + 0, + 0); +} + +void setInterpolationMode( + Gdiplus::Graphics& rGraphics, + const long& rSrcWidth, + const long& rDestWidth, + const long& rSrcHeight, + const long& rDestHeight) +{ + const bool bSameWidth(rSrcWidth == rDestWidth); + const bool bSameHeight(rSrcHeight == rDestHeight); + + if(bSameWidth && bSameHeight) + { +#ifdef __MINGW32__ + //Gdiplus::InterpolationModeInvalid is missing on mingw + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); +#else + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid); +#endif + } + else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight) + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); + } + else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight) + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); + } + else + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); + } +} + +bool WinSalGraphicsImpl::tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap) +{ + if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) + { + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); + + if(aARGB.get()) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + + setInterpolationMode( + aGraphics, + rTR.mnSrcWidth, + rTR.mnDestWidth, + rTR.mnSrcHeight, + rTR.mnDestHeight); + + paintToGdiPlus( + aGraphics, + rTR, + *aARGB.get()); + + return true; + } + } + + return false; +} + +bool WinSalGraphicsImpl::drawAlphaBitmap( + const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, + const SalBitmap& rAlphaBmp) +{ + if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) + { + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); + const WinSalBitmap& rSalAlpha = static_cast< const WinSalBitmap& >(rAlphaBmp); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(&rSalAlpha)); + + if(aARGB.get()) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + + setInterpolationMode( + aGraphics, + rTR.mnSrcWidth, + rTR.mnDestWidth, + rTR.mnSrcHeight, + rTR.mnDestHeight); + + paintToGdiPlus( + aGraphics, + rTR, + *aARGB.get()); + + return true; + } + } + + return false; +} + +bool WinSalGraphicsImpl::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); + const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); + + if(aARGB.get()) + { + const long nSrcWidth(aARGB->GetWidth()); + const long nSrcHeight(aARGB->GetHeight()); + + if(nSrcWidth && nSrcHeight) + { + const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); + const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); + + if(nDestWidth && nDestHeight) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + Gdiplus::PointF aDestPoints[3]; + Gdiplus::ImageAttributes aAttributes; + + setInterpolationMode( + aGraphics, + nSrcWidth, + nDestWidth, + nSrcHeight, + nDestHeight); + + // this mode is only capable of drawing the whole bitmap to a paralellogram + aDestPoints[0].X = Gdiplus::REAL(rNull.getX()); + aDestPoints[0].Y = Gdiplus::REAL(rNull.getY()); + aDestPoints[1].X = Gdiplus::REAL(rX.getX()); + aDestPoints[1].Y = Gdiplus::REAL(rX.getY()); + aDestPoints[2].X = Gdiplus::REAL(rY.getX()); + aDestPoints[2].Y = Gdiplus::REAL(rY.getY()); + + aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); + + aGraphics.DrawImage( + aARGB.get(), + aDestPoints, + 3, + Gdiplus::REAL(0.0), + Gdiplus::REAL(0.0), + Gdiplus::REAL(nSrcWidth), + Gdiplus::REAL(nSrcHeight), + Gdiplus::UnitPixel, + &aAttributes, + 0, + 0); + } + } + + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/gdiimpl.hxx b/vcl/win/source/gdi/gdiimpl.hxx new file mode 100644 index 000000000000..d1b5cfd4d72b --- /dev/null +++ b/vcl/win/source/gdi/gdiimpl.hxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "salgdiimpl.hxx" + +#include "win/svsys.h" + +class WinSalGraphics; + +class WinSalGraphicsImpl : public SalGraphicsImpl +{ +private: + + WinSalGraphics& mrParent; + bool mbXORMode : 1; // _every_ output with RasterOp XOR + bool mbPen : 1; // is Pen (FALSE == NULL_PEN) + HPEN mhPen; // Pen + bool mbStockPen : 1; // is Pen a stockpen + bool mbBrush : 1; // is Brush (FALSE == NULL_BRUSH) + bool mbStockBrush : 1; // is Brush a stcokbrush + HBRUSH mhBrush; // Brush + COLORREF mnPenColor; // PenColor + COLORREF mnBrushColor; // BrushColor + + // remember RGB values for SetLineColor/SetFillColor + SalColor maLineColor; + SalColor maFillColor; + + bool tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap); + +public: + + WinSalGraphicsImpl(WinSalGraphics& rParent); + + virtual ~WinSalGraphicsImpl(); + + virtual void freeResources() SAL_OVERRIDE; + + virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; + + // get the width of the device + virtual long GetGraphicsWidth() const SAL_OVERRIDE; + + // set the clip region to empty + virtual void ResetClipRegion() SAL_OVERRIDE; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() SAL_OVERRIDE; + + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ) SAL_OVERRIDE; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() SAL_OVERRIDE; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ) SAL_OVERRIDE; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) SAL_OVERRIDE; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) SAL_OVERRIDE; + virtual void drawPixel( long nX, long nY, SalColor nSalColor ) SAL_OVERRIDE; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) SAL_OVERRIDE; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) SAL_OVERRIDE; + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) SAL_OVERRIDE; + + virtual bool drawPolyLine( + const ::basegfx::B2DPolygon&, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin, + com::sun::star::drawing::LineCap) SAL_OVERRIDE; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) SAL_OVERRIDE; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) SAL_OVERRIDE; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) SAL_OVERRIDE; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) SAL_OVERRIDE; + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual SalColor getPixel( long nX, long nY ) SAL_OVERRIDE; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) SAL_OVERRIDE; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) SAL_OVERRIDE; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uLong nSize ) SAL_OVERRIDE; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) SAL_OVERRIDE; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) SAL_OVERRIDE; + + /** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) SAL_OVERRIDE; + + + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx index be4a6c8e8fe9..28469eb1a017 100644 --- a/vcl/win/source/gdi/salgdi.cxx +++ b/vcl/win/source/gdi/salgdi.cxx @@ -32,6 +32,9 @@ #include #include +#include "salgdiimpl.hxx" +#include "gdiimpl.hxx" + // comment out to prevent use of beziers on GDI functions #define USE_GDI_BEZIERS @@ -106,9 +109,6 @@ static BYTE aOrdDither16Bit[8][8] = // complex is set #define GSL_PEN_WIDTH 1 -#define SAL_POLYPOLYCOUNT_STACKBUF 8 -#define SAL_POLYPOLYPOINTS_STACKBUF 64 - void ImplInitSalGDI() { SalData* pSalData = GetSalData(); @@ -365,6 +365,23 @@ void ImplFreeSalGDI() pSalData->mbResourcesAlreadyFreed = true; } +int ImplIsSysColorEntry( SalColor nSalColor ) +{ + SysColorEntry* pEntry = pFirstSysColor; + const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + + while ( pEntry ) + { + if ( pEntry->nRGB == nTestRGB ) + return TRUE; + pEntry = pEntry->pNext; + } + + return FALSE; +} + static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue ) { // dither color? @@ -391,23 +408,6 @@ static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue ) return FALSE; } -int ImplIsSysColorEntry( SalColor nSalColor ) -{ - SysColorEntry* pEntry = pFirstSysColor; - const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - - while ( pEntry ) - { - if ( pEntry->nRGB == nTestRGB ) - return TRUE; - pEntry = pEntry->pNext; - } - - return FALSE; -} - static void ImplInsertSysColorEntry( int nSysIndex ) { const DWORD nRGB = GetSysColor( nSysIndex ); @@ -466,16 +466,6 @@ void ImplUpdateSysColorEntries() ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT ); } -static SalColor ImplGetROPSalColor( SalROPColor nROPColor ) -{ - SalColor nSalColor; - if ( nROPColor == SAL_ROP_0 ) - nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); - else - nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); - return nSalColor; -} - void ImplSalInitGraphics( WinSalGraphics* pData ) { // calculate the minimal line width for the printer @@ -566,106 +556,8 @@ void ImplClearHDCCache( SalData* pData ) } } -// #100127# Fill point and flag memory from array of points which -// might also contain bezier control points for the PolyDraw() GDI method -// Make sure pWinPointAry and pWinFlagAry are big enough -void ImplPreparePolyDraw( bool bCloseFigures, - sal_uLong nPoly, - const sal_uInt32* pPoints, - const SalPoint* const* pPtAry, - const BYTE* const* pFlgAry, - POINT* pWinPointAry, - BYTE* pWinFlagAry ) -{ - sal_uLong nCurrPoly; - for( nCurrPoly=0; nCurrPoly( *pPtAry++ ); - const BYTE* pCurrFlag = *pFlgAry++; - const sal_uInt32 nCurrPoints = *pPoints++; - const bool bHaveFlagArray( pCurrFlag ); - sal_uLong nCurrPoint; - - if( nCurrPoints ) - { - // start figure - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_MOVETO; - ++pCurrFlag; - - for( nCurrPoint=1; nCurrPointmnX, pPtAry->mnY, NULL ); - ++pPtAry; ++pFlgAry; - - for( i=1; imnX, pPtAry->mnY ); - } - else if( nPoints - i > 2 ) - { - PolyBezierTo( hdc, reinterpret_cast(pPtAry), 3 ); - i += 2; pPtAry += 2; pFlgAry += 2; - } - } - } -} - -WinSalGraphics::WinSalGraphics() +WinSalGraphics::WinSalGraphics(): + mpImpl(new WinSalGraphicsImpl(*this)) { for( int i = 0; i < MAX_FALLBACK; ++i ) { @@ -678,8 +570,6 @@ WinSalGraphics::WinSalGraphics() mfCurrentFontScale = 1.0; mhLocalDC = 0; - mhPen = 0; - mhBrush = 0; mhRegion = 0; mhDefPen = 0; mhDefBrush = 0; @@ -693,7 +583,6 @@ WinSalGraphics::WinSalGraphics() mpFontKernPairs = NULL; mnFontKernPairCount = 0; mbFontKernInit = FALSE; - mbXORMode = FALSE; mnPenWidth = GSL_PEN_WIDTH; } @@ -702,17 +591,6 @@ WinSalGraphics::~WinSalGraphics() // free obsolete GDI objects ReleaseFonts(); - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } - if ( mhRegion ) { DeleteRegion( mhRegion ); @@ -730,6 +608,11 @@ WinSalGraphics::~WinSalGraphics() delete mpFontKernPairs; } +HWND WinSalGraphics::gethWnd() +{ + return mhWnd; +} + void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) { rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX ); @@ -744,839 +627,111 @@ void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) sal_uInt16 WinSalGraphics::GetBitCount() const { - return (sal_uInt16)GetDeviceCaps( getHDC(), BITSPIXEL ); + return mpImpl->GetBitCount(); } long WinSalGraphics::GetGraphicsWidth() const { - if( mhWnd && IsWindow( mhWnd ) ) - { - WinSalFrame* pFrame = GetWindowPtr( mhWnd ); - if( pFrame ) - { - if( pFrame->maGeometry.nWidth ) - return pFrame->maGeometry.nWidth; - else - { - // TODO: perhaps not needed, maGeometry should always be up-to-date - RECT aRect; - GetClientRect( mhWnd, &aRect ); - return aRect.right; - } - } - } - - return 0; + return mpImpl->GetGraphicsWidth(); } void WinSalGraphics::ResetClipRegion() { - if ( mhRegion ) - { - DeleteRegion( mhRegion ); - mhRegion = 0; - } - - SelectClipRgn( getHDC(), 0 ); + mpImpl->ResetClipRegion(); } bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip ) { - if ( mhRegion ) - { - DeleteRegion( mhRegion ); - mhRegion = 0; - } - - bool bUsePolygon(i_rClip.HasPolyPolygonOrB2DPolyPolygon()); - static bool bTryToAvoidPolygon(true); - - // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve - // and only contains horizontal/vertical edges. In that case, use the fallback - // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do - // the correct polygon-to-RegionBand transformation. - // Background is that when using the same Rectangle as rectangle or as Polygon - // clip region will lead to different results; the polygon-based one will be - // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This - // again is because of the polygon-nature and it's classic handling when filling. - // This also means that all cases which use a 'true' polygon-based incarnation of - // a vcl::Region should know what they do - it may lead to repaint errors. - if(bUsePolygon && bTryToAvoidPolygon) - { - const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); - - if(!aPolyPolygon.areControlPointsUsed()) - { - if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon)) - { - bUsePolygon = false; - } - } - } - - if(bUsePolygon) - { - // #i122149# check the comment above to know that this may lead to potential repaint - // problems. It may be solved (if needed) by scaling the polygon by one in X - // and Y. Currently the workaround to only use it if really unavoidable will - // solve most cases. When someone is really using polygon-based Regions he - // should know what he is doing. - // Added code to do that scaling to check if it works, testing it. - const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); - const sal_uInt32 nCount(aPolyPolygon.count()); - - if( nCount ) - { - std::vector< POINT > aPolyPoints; - aPolyPoints.reserve( 1024 ); - std::vector< INT > aPolyCounts( nCount, 0 ); - basegfx::B2DHomMatrix aExpand; - static bool bExpandByOneInXandY(true); - - if(bExpandByOneInXandY) - { - const basegfx::B2DRange aRangeS(aPolyPolygon.getB2DRange()); - const basegfx::B2DRange aRangeT(aRangeS.getMinimum(), aRangeS.getMaximum() + basegfx::B2DTuple(1.0, 1.0)); - aExpand = basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS, aRangeT)); - } - - for(sal_uInt32 a(0); a < nCount; a++) - { - const basegfx::B2DPolygon aPoly( - basegfx::tools::adaptiveSubdivideByDistance( - aPolyPolygon.getB2DPolygon(a), - 1)); - const sal_uInt32 nPoints(aPoly.count()); - aPolyCounts[a] = nPoints; - - for( sal_uInt32 b = 0; b < nPoints; b++ ) - { - basegfx::B2DPoint aPt(aPoly.getB2DPoint(b)); - - if(bExpandByOneInXandY) - { - aPt = aExpand * aPt; - } - - POINT aPOINT; - // #i122149# do correct rounding - aPOINT.x = basegfx::fround(aPt.getX()); - aPOINT.y = basegfx::fround(aPt.getY()); - aPolyPoints.push_back( aPOINT ); - } - } - - mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE ); - } - } - else - { - RectangleVector aRectangles; - i_rClip.GetRegionRectangles(aRectangles); - - sal_uLong nRectBufSize = sizeof(RECT)*aRectangles.size(); - if ( aRectangles.size() < SAL_CLIPRECT_COUNT ) - { - if ( !mpStdClipRgnData ) - mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; - mpClipRgnData = mpStdClipRgnData; - } - else - mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; - mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); - mpClipRgnData->rdh.iType = RDH_RECTANGLES; - mpClipRgnData->rdh.nCount = aRectangles.size(); - mpClipRgnData->rdh.nRgnSize = nRectBufSize; - RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound); - SetRectEmpty( pBoundRect ); - RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer)); - bool bFirstClipRect = true; - - for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) - { - const long nW(aRectIter->GetWidth()); - const long nH(aRectIter->GetHeight()); - - if(nW && nH) - { - const long nRight(aRectIter->Left() + nW); - const long nBottom(aRectIter->Top() + nH); - - if(bFirstClipRect) - { - pBoundRect->left = aRectIter->Left(); - pBoundRect->top = aRectIter->Top(); - pBoundRect->right = nRight; - pBoundRect->bottom = nBottom; - bFirstClipRect = false; - } - else - { - if(aRectIter->Left() < pBoundRect->left) - { - pBoundRect->left = (int)aRectIter->Left(); - } - - if(aRectIter->Top() < pBoundRect->top) - { - pBoundRect->top = (int)aRectIter->Top(); - } - - if(nRight > pBoundRect->right) - { - pBoundRect->right = (int)nRight; - } - - if(nBottom > pBoundRect->bottom) - { - pBoundRect->bottom = (int)nBottom; - } - } - - pNextClipRect->left = (int)aRectIter->Left(); - pNextClipRect->top = (int)aRectIter->Top(); - pNextClipRect->right = (int)nRight; - pNextClipRect->bottom = (int)nBottom; - pNextClipRect++; - } - else - { - mpClipRgnData->rdh.nCount--; - mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); - } - } - - // create clip region from ClipRgnData - if(0 == mpClipRgnData->rdh.nCount) - { - // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given - // that contains no polygons or only empty ones (no width/height). This is - // perfectly fine and we are done, except setting it (see end of method) - } - else if(1 == mpClipRgnData->rdh.nCount) - { - RECT* pRect = &(mpClipRgnData->rdh.rcBound); - mhRegion = CreateRectRgn( pRect->left, pRect->top, - pRect->right, pRect->bottom ); - } - else if(mpClipRgnData->rdh.nCount > 1) - { - sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); - mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData ); - - // if ExtCreateRegion(...) is not supported - if( !mhRegion ) - { - RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData; - - if( pHeader->nCount ) - { - RECT* pRect = (RECT*) mpClipRgnData->Buffer; - mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); - pRect++; - - for( sal_uLong n = 1; n < pHeader->nCount; n++, pRect++ ) - { - HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); - CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR ); - DeleteRegion( hRgn ); - } - } - } - - if ( mpClipRgnData != mpStdClipRgnData ) - delete [] mpClipRgnData; - } - } - - if( mhRegion ) - { - SelectClipRgn( getHDC(), mhRegion ); - - // debug code if you weant to check range of the newly applied ClipRegion - //RECT aBound; - //const int aRegionType = GetRgnBox(mhRegion, &aBound); - - //bool bBla = true; - } - else - { - // #i123585# See above, this is a valid case, execute it - SelectClipRgn( getHDC(), 0 ); - } - - // #i123585# retval no longer dependent of mhRegion, see TaskId comments above - return true; + return mpImpl->setClipRegion( i_rClip ); } void WinSalGraphics::SetLineColor() { - // create and select new pen - HPEN hNewPen = GetStockPen( NULL_PEN ); - HPEN hOldPen = SelectPen( getHDC(), hNewPen ); - - // destroy or save old pen - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - else - mhDefPen = hOldPen; - - // set new data - mhPen = hNewPen; - mbPen = FALSE; - mbStockPen = TRUE; + mpImpl->SetLineColor(); } void WinSalGraphics::SetLineColor( SalColor nSalColor ) { - maLineColor = nSalColor; - COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - HPEN hNewPen = 0; - bool bStockPen = FALSE; - - // search for stock pen (only screen, because printer have problems, - // when we use stock objects) - if ( !mbPrinter ) - { - SalData* pSalData = GetSalData(); - for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ ) - { - if ( nPenColor == pSalData->maStockPenColorAry[i] ) - { - hNewPen = pSalData->mhStockPenAry[i]; - bStockPen = TRUE; - break; - } - } - } - - // create new pen - if ( !hNewPen ) - { - if ( !mbPrinter ) - { - if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) ) - nPenColor = PALRGB_TO_RGB( nPenColor ); - } - - hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor ); - bStockPen = FALSE; - } - - // select new pen - HPEN hOldPen = SelectPen( getHDC(), hNewPen ); - - // destroy or save old pen - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - else - mhDefPen = hOldPen; - - // set new data - mnPenColor = nPenColor; - mhPen = hNewPen; - mbPen = TRUE; - mbStockPen = bStockPen; + mpImpl->SetLineColor( nSalColor ); } void WinSalGraphics::SetFillColor() { - // create and select new brush - HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush ); - - // destroy or save old brush - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } - else - mhDefBrush = hOldBrush; - - // set new data - mhBrush = hNewBrush; - mbBrush = FALSE; - mbStockBrush = TRUE; + mpImpl->SetFillColor(); } void WinSalGraphics::SetFillColor( SalColor nSalColor ) { - maFillColor = nSalColor; - SalData* pSalData = GetSalData(); - BYTE nRed = SALCOLOR_RED( nSalColor ); - BYTE nGreen = SALCOLOR_GREEN( nSalColor ); - BYTE nBlue = SALCOLOR_BLUE( nSalColor ); - COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue ); - HBRUSH hNewBrush = 0; - bool bStockBrush = FALSE; - - // search for stock brush (only screen, because printer have problems, - // when we use stock objects) - if ( !mbPrinter ) - { - for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ ) - { - if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] ) - { - hNewBrush = pSalData->mhStockBrushAry[i]; - bStockBrush = TRUE; - break; - } - } - } - - // create new brush - if ( !hNewBrush ) - { - if ( mbPrinter || !pSalData->mhDitherDIB ) - hNewBrush = CreateSolidBrush( nBrushColor ); - else - { - if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount ) - { - BYTE* pTmp = pSalData->mpDitherDIBData; - long* pDitherDiff = pSalData->mpDitherDiff; - BYTE* pDitherLow = pSalData->mpDitherLow; - BYTE* pDitherHigh = pSalData->mpDitherHigh; - - for( long nY = 0L; nY < 8L; nY++ ) - { - for( long nX = 0L; nX < 8L; nX++ ) - { - const long nThres = aOrdDither16Bit[ nY ][ nX ]; - *pTmp++ = DMAP( nBlue, nThres ); - *pTmp++ = DMAP( nGreen, nThres ); - *pTmp++ = DMAP( nRed, nThres ); - } - } - - hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS ); - } - else if ( ImplIsSysColorEntry( nSalColor ) ) - { - nBrushColor = PALRGB_TO_RGB( nBrushColor ); - hNewBrush = CreateSolidBrush( nBrushColor ); - } - else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) ) - hNewBrush = CreateSolidBrush( nBrushColor ); - else - { - BYTE* pTmp = pSalData->mpDitherDIBData; - long* pDitherDiff = pSalData->mpDitherDiff; - BYTE* pDitherLow = pSalData->mpDitherLow; - BYTE* pDitherHigh = pSalData->mpDitherHigh; - - for ( long nY = 0L; nY < 8L; nY++ ) - { - for ( long nX = 0L; nX < 8L; nX++ ) - { - const long nThres = aOrdDither8Bit[ nY ][ nX ]; - *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36; - pTmp++; - } - } - - hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS ); - } - } - - bStockBrush = FALSE; - } - - // select new brush - HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush ); - - // destroy or save old brush - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } - else - mhDefBrush = hOldBrush; - - // set new data - mnBrushColor = nBrushColor; - mhBrush = hNewBrush; - mbBrush = TRUE; - mbStockBrush = bStockBrush; + mpImpl->SetFillColor( nSalColor ); } -void WinSalGraphics::SetXORMode( bool bSet, bool ) +void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) { - mbXORMode = bSet; - ::SetROP2( getHDC(), bSet ? R2_XORPEN : R2_COPYPEN ); + mpImpl->SetXORMode( bSet, bInvertOnly ); } void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor ) { - SetLineColor( ImplGetROPSalColor( nROPColor ) ); + mpImpl->SetROPLineColor( nROPColor ); } void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor ) { - SetFillColor( ImplGetROPSalColor( nROPColor ) ); + mpImpl->SetROPFillColor( nROPColor ); } void WinSalGraphics::drawPixel( long nX, long nY ) { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)nX, (int)nY, mnPenColor ); + mpImpl->drawPixel( nX, nY ); } void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) { - COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - - if ( !mbPrinter && - GetSalData()->mhDitherPal && - ImplIsSysColorEntry( nSalColor ) ) - nCol = PALRGB_TO_RGB( nCol ); - - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( nCol ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - ::SetPixel( getHDC(), (int)nX, (int)nY, nCol ); + mpImpl->drawPixel( nX, nY, nSalColor ); } void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) { - MoveToEx( getHDC(), (int)nX1, (int)nY1, NULL ); - - // we must paint the endpoint - int bPaintEnd = TRUE; - if ( nX1 == nX2 ) - { - bPaintEnd = FALSE; - if ( nY1 <= nY2 ) - nY2++; - else - nY2--; - } - if ( nY1 == nY2 ) - { - bPaintEnd = FALSE; - if ( nX1 <= nX2 ) - nX2++; - else - nX2--; - } - - LineTo( getHDC(), (int)nX2, (int)nY2 ); - - if ( bPaintEnd && !mbPrinter ) - { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)nX2, (int)nY2, mnPenColor ); - } + mpImpl->drawLine( nX1, nY1, nX2, nY2 ); } void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) { - if ( !mbPen ) - { - if ( !mbPrinter ) - { - PatBlt( getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight, - mbXORMode ? PATINVERT : PATCOPY ); - } - else - { - RECT aWinRect; - aWinRect.left = nX; - aWinRect.top = nY; - aWinRect.right = nX+nWidth; - aWinRect.bottom = nY+nHeight; - ::FillRect( getHDC(), &aWinRect, mhBrush ); - } - } - else - WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); + mpImpl->drawRect( nX, nY, nWidth, nHeight ); } void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) { - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" ); - - POINT* pWinPtAry = (POINT*)pPtAry; - - // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN) - // we must paint the endpoint for last line - BOOL bPaintEnd = TRUE; - if ( pWinPtAry[nPoints-2].x == pWinPtAry[nPoints-1].x ) - { - bPaintEnd = FALSE; - if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y ) - pWinPtAry[nPoints-1].y++; - else - pWinPtAry[nPoints-1].y--; - } - if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y ) - { - bPaintEnd = FALSE; - if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x ) - pWinPtAry[nPoints-1].x++; - else - pWinPtAry[nPoints-1].x--; - } - - // for Windows 95 and its maximum number of points - if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - - if ( bPaintEnd && !mbPrinter ) - { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), mnPenColor ); - } + mpImpl->drawPolyLine( nPoints, pPtAry ); } void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) { - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolygon(): POINT != SalPoint" ); - - POINT* pWinPtAry = (POINT*)pPtAry; - // for Windows 95 and its maximum number of points - if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + mpImpl->drawPolygon( nPoints, pPtAry ); } void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) { - UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF]; - UINT* pWinPointAry; - UINT nPolyPolyPoints = 0; - UINT nPoints; - UINT i; - - if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF ) - pWinPointAry = aWinPointAry; - else - pWinPointAry = new UINT[nPoly]; - - for ( i = 0; i < (UINT)nPoly; i++ ) - { - nPoints = (UINT)pPoints[i]+1; - pWinPointAry[i] = nPoints; - nPolyPolyPoints += nPoints; - } - - POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF]; - POINT* pWinPointAryAry; - if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF ) - pWinPointAryAry = aWinPointAryAry; - else - pWinPointAryAry = new POINT[nPolyPolyPoints]; - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" ); - const SalPoint* pPolyAry; - UINT n = 0; - for ( i = 0; i < (UINT)nPoly; i++ ) - { - nPoints = pWinPointAry[i]; - pPolyAry = pPtAry[i]; - memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) ); - pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n]; - n += nPoints; - } - - if ( !WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) && - (nPolyPolyPoints > MAX_64KSALPOINTS) ) - { - nPolyPolyPoints = 0; - nPoly = 0; - do - { - nPolyPolyPoints += pWinPointAry[(UINT)nPoly]; - nPoly++; - } - while ( nPolyPolyPoints < MAX_64KSALPOINTS ); - nPoly--; - if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS ) - pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS; - if ( nPoly == 1 ) - WIN_Polygon( getHDC(), pWinPointAryAry, *pWinPointAry ); - else - WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly ); - } - - if ( pWinPointAry != aWinPointAry ) - delete [] pWinPointAry; - if ( pWinPointAryAry != aWinPointAryAry ) - delete [] pWinPointAryAry; + mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry ); } -#define SAL_POLY_STACKBUF 32 - bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" ); - - ImplRenderPath( getHDC(), nPoints, pPtAry, pFlgAry ); - - return true; -#else - return false; -#endif + return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry ); } bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" ); - - POINT aStackAry1[SAL_POLY_STACKBUF]; - BYTE aStackAry2[SAL_POLY_STACKBUF]; - POINT* pWinPointAry; - BYTE* pWinFlagAry; - if( nPoints > SAL_POLY_STACKBUF ) - { - pWinPointAry = new POINT[ nPoints ]; - pWinFlagAry = new BYTE[ nPoints ]; - } - else - { - pWinPointAry = aStackAry1; - pWinFlagAry = aStackAry2; - } - - sal_uInt32 nPoints_i32(nPoints); - ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry); - - bool bRet( false ); - - if( BeginPath( getHDC() ) ) - { - PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nPoints); - - if( EndPath( getHDC() ) ) - { - if( StrokeAndFillPath( getHDC() ) ) - bRet = true; - } - } - - if( pWinPointAry != aStackAry1 ) - { - delete [] pWinPointAry; - delete [] pWinFlagAry; - } - - return bRet; -#else - return false; -#endif + return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry ); } bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" ); - - sal_uLong nCurrPoly, nTotalPoints; - const sal_uInt32* pCurrPoints = pPoints; - for( nCurrPoly=0, nTotalPoints=0; nCurrPoly SAL_POLY_STACKBUF ) - { - pWinPointAry = new POINT[ nTotalPoints ]; - pWinFlagAry = new BYTE[ nTotalPoints ]; - } - else - { - pWinPointAry = aStackAry1; - pWinFlagAry = aStackAry2; - } - - ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry); - - bool bRet( false ); - - if( BeginPath( getHDC() ) ) - { - PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints); - - if( EndPath( getHDC() ) ) - { - if( StrokeAndFillPath( getHDC() ) ) - bRet = true; - } - } - - if( pWinPointAry != aStackAry1 ) - { - delete [] pWinPointAry; - delete [] pWinFlagAry; - } - - return bRet; -#else - return false; -#endif + return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry ); } -#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF - static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize ) { while ( nComp-- >= nSize ) @@ -1656,6 +811,8 @@ static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize ) return bRetValue; } +#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF + bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize ) { bool bRetValue = false; diff --git a/vcl/win/source/gdi/salgdi2.cxx b/vcl/win/source/gdi/salgdi2.cxx index 16f262fa41c6..f00945164f3e 100644 --- a/vcl/win/source/gdi/salgdi2.cxx +++ b/vcl/win/source/gdi/salgdi2.cxx @@ -33,6 +33,7 @@ #include "vcl/salbtype.hxx" #include "vcl/bmpacc.hxx" #include "outdata.hxx" +#include "salgdiimpl.hxx" bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const { @@ -56,82 +57,7 @@ bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const void WinSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) { - HDC hSrcDC; - DWORD nRop; - - if ( pSrcGraphics ) - hSrcDC = static_cast(pSrcGraphics)->getHDC(); - else - hSrcDC = getHDC(); - - if ( mbXORMode ) - nRop = SRCINVERT; - else - nRop = SRCCOPY; - - if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && - (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) - { - BitBlt( getHDC(), - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hSrcDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - nRop ); - } - else - { - int nOldStretchMode = SetStretchBltMode( getHDC(), STRETCH_DELETESCANS ); - StretchBlt( getHDC(), - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hSrcDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - nRop ); - SetStretchBltMode( getHDC(), nOldStretchMode ); - } -} - -void ImplCalcOutSideRgn( const RECT& rSrcRect, - int nLeft, int nTop, int nRight, int nBottom, - HRGN& rhInvalidateRgn ) -{ - HRGN hTempRgn; - - // calculate area outside the visible region - if ( rSrcRect.left < nLeft ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.top < nTop ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.right > nRight ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.bottom > nBottom ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } + mpImpl->copyBits( rPosAry, pSrcGraphics ); } void WinSalGraphics::copyArea( long nDestX, long nDestY, @@ -139,688 +65,60 @@ void WinSalGraphics::copyArea( long nDestX, long nDestY, long nSrcWidth, long nSrcHeight, sal_uInt16 nFlags ) { - bool bRestoreClipRgn = false; - HRGN hOldClipRgn = 0; - int nOldClipRgnType = ERROR; - HRGN hInvalidateRgn = 0; - - // do we have to invalidate also the overlapping regions? - if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow ) - { - // compute and invalidate those parts that were either off-screen or covered by other windows - // while performing the above BitBlt - // those regions then have to be invalidated as they contain useless/wrong data - RECT aSrcRect; - RECT aClipRect; - RECT aTempRect; - RECT aTempRect2; - HRGN hTempRgn; - HWND hWnd; - - // restrict srcRect to this window (calc intersection) - aSrcRect.left = (int)nSrcX; - aSrcRect.top = (int)nSrcY; - aSrcRect.right = aSrcRect.left+(int)nSrcWidth; - aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight; - GetClientRect( mhWnd, &aClipRect ); - if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) ) - { - // transform srcRect to screen coordinates - POINT aPt; - aPt.x = 0; - aPt.y = 0; - ClientToScreen( mhWnd, &aPt ); - aSrcRect.left += aPt.x; - aSrcRect.top += aPt.y; - aSrcRect.right += aPt.x; - aSrcRect.bottom += aPt.y; - hInvalidateRgn = 0; - - // compute the parts that are off screen (ie invisible) - RECT theScreen; - ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account - ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn ); - - // calculate regions that are covered by other windows - HRGN hTempRgn2 = 0; - HWND hWndTopWindow = mhWnd; - // Find the TopLevel Window, because only Windows which are in - // in the foreground of our TopLevel window must be considered - if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ) - { - RECT aTempRect3 = aSrcRect; - do - { - hWndTopWindow = ::GetParent( hWndTopWindow ); - - // Test if the Parent clips our window - GetClientRect( hWndTopWindow, &aTempRect ); - POINT aPt2; - aPt2.x = 0; - aPt2.y = 0; - ClientToScreen( hWndTopWindow, &aPt2 ); - aTempRect.left += aPt2.x; - aTempRect.top += aPt2.y; - aTempRect.right += aPt2.x; - aTempRect.bottom += aPt2.y; - IntersectRect( &aTempRect3, &aTempRect3, &aTempRect ); - } - while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ); - - // If one or more Parents clip our window, than we must - // calculate the outside area - if ( !EqualRect( &aSrcRect, &aTempRect3 ) ) - { - ImplCalcOutSideRgn( aSrcRect, - aTempRect3.left, aTempRect3.top, - aTempRect3.right, aTempRect3.bottom, - hInvalidateRgn ); - } - } - // retrieve the top-most (z-order) child window - hWnd = GetWindow( GetDesktopWindow(), GW_CHILD ); - while ( hWnd ) - { - if ( hWnd == hWndTopWindow ) - break; - if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) ) - { - GetWindowRect( hWnd, &aTempRect ); - if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) ) - { - // hWnd covers part or all of aSrcRect - if ( !hInvalidateRgn ) - hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect ); - - // get full bounding box of hWnd - hTempRgn = CreateRectRgnIndirect( &aTempRect ); - - // get region of hWnd (the window may be shaped) - if ( !hTempRgn2 ) - hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 ); - int nRgnType = GetWindowRgn( hWnd, hTempRgn2 ); - if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) - { - // convert window region to screen coordinates - OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top ); - // and intersect with the window's bounding box - CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND ); - } - // finally compute that part of aSrcRect which is not covered by any parts of hWnd - CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - } - // retrieve the next window in the z-order, i.e. the window below hwnd - hWnd = GetWindow( hWnd, GW_HWNDNEXT ); - } - if ( hTempRgn2 ) - DeleteRegion( hTempRgn2 ); - if ( hInvalidateRgn ) - { - // hInvalidateRgn contains the fully visible parts of the original srcRect - hTempRgn = CreateRectRgnIndirect( &aSrcRect ); - // substract it from the original rect to get the occluded parts - int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - - if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) - { - // move the occluded parts to the destination pos - int nOffX = (int)(nDestX-nSrcX); - int nOffY = (int)(nDestY-nSrcY); - OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y ); - - // by excluding hInvalidateRgn from the system's clip region - // we will prevent bitblt from copying useless data - // epsecially now shadows from overlapping windows will appear (#i36344) - hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 ); - nOldClipRgnType = GetClipRgn( getHDC(), hOldClipRgn ); - - bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate - ExtSelectClipRgn( getHDC(), hInvalidateRgn, RGN_DIFF ); - } - } - } - } - - BitBlt( getHDC(), - (int)nDestX, (int)nDestY, - (int)nSrcWidth, (int)nSrcHeight, - getHDC(), - (int)nSrcX, (int)nSrcY, - SRCCOPY ); - - if( bRestoreClipRgn ) - { - // restore old clip region - if( nOldClipRgnType != ERROR ) - SelectClipRgn( getHDC(), hOldClipRgn); - DeleteRegion( hOldClipRgn ); - - // invalidate regions that were not copied - bool bInvalidate = true; - - // Combine Invalidate vcl::Region with existing ClipRegion - HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 ); - if ( GetClipRgn( getHDC(), hTempRgn ) == 1 ) - { - int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND ); - if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) ) - bInvalidate = false; - } - DeleteRegion( hTempRgn ); - - if ( bInvalidate ) - { - InvalidateRgn( mhWnd, hInvalidateRgn, TRUE ); - // here we only initiate an update if this is the MainThread, - // so that there is no deadlock when handling the Paint event, - // as the SolarMutex is already held by this Thread - SalData* pSalData = GetSalData(); - DWORD nCurThreadId = GetCurrentThreadId(); - if ( pSalData->mnAppThreadId == nCurThreadId ) - UpdateWindow( mhWnd ); - } - - DeleteRegion( hInvalidateRgn ); - } - -} - -void ImplDrawBitmap( HDC hDC, - const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap, - bool bPrinter, int nDrawMode ) -{ - if( hDC ) - { - HGLOBAL hDrawDIB; - HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB(); - WinSalBitmap* pTmpSalBmp = NULL; - bool bPrintDDB = ( bPrinter && hDrawDDB ); - - if( bPrintDDB ) - { - pTmpSalBmp = new WinSalBitmap; - pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() ); - hDrawDIB = pTmpSalBmp->ImplGethDIB(); - } - else - hDrawDIB = rSalBitmap.ImplGethDIB(); - - if( hDrawDIB ) - { - PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); - PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; - PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + - rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); - const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); - - StretchDIBits( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - (int)rPosAry.mnSrcX, (int)(pBIH->biHeight - rPosAry.mnSrcHeight - rPosAry.mnSrcY), - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - pBits, pBI, DIB_RGB_COLORS, nDrawMode ); - - GlobalUnlock( hDrawDIB ); - SetStretchBltMode( hDC, nOldStretchMode ); - } - else if( hDrawDDB && !bPrintDDB ) - { - HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB ); - COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF); - COLORREF nOldTextColor = RGB(0,0,0); - bool bMono = ( rSalBitmap.GetBitCount() == 1 ); - - if( bMono ) - { - COLORREF nBkColor = RGB( 0xFF, 0xFF, 0xFF ); - COLORREF nTextColor = RGB( 0x00, 0x00, 0x00 ); - //fdo#33455 handle 1 bit depth pngs with palette entries - //to set fore/back colors - if (const BitmapBuffer* pBitmapBuffer = const_cast(rSalBitmap).AcquireBuffer(true)) - { - const BitmapPalette& rPalette = pBitmapBuffer->maPalette; - if (rPalette.GetEntryCount() == 2) - { - SalColor nCol; - nCol = ImplColorToSal(rPalette[0]); - nTextColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); - nCol = ImplColorToSal(rPalette[1]); - nBkColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); - } - } - nOldBkColor = SetBkColor( hDC, nBkColor ); - nOldTextColor = ::SetTextColor( hDC, nTextColor ); - } - - if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && - (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) - { - BitBlt( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hBmpDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - nDrawMode ); - } - else - { - const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); - - StretchBlt( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hBmpDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - nDrawMode ); - - SetStretchBltMode( hDC, nOldStretchMode ); - } - - if( bMono ) - { - SetBkColor( hDC, nOldBkColor ); - ::SetTextColor( hDC, nOldTextColor ); - } - - ImplReleaseCachedDC( CACHED_HDC_DRAW ); - } - - if( bPrintDDB ) - delete pTmpSalBmp; - } + mpImpl->copyArea( nDestX, nDestY, nSrcX, nSrcY, + nSrcWidth, nSrcHeight, nFlags ); } void WinSalGraphics::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) { - bool bTryDirectPaint(!mbPrinter && !mbXORMode); - - if(bTryDirectPaint) - { - // only paint direct when no scaling and no MapMode, else the - // more expensive conversions may be done for short-time Bitmap/BitmapEx - // used for buffering only - if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) - { - bTryDirectPaint = false; - } - } - - // try to draw using GdiPlus directly - if(bTryDirectPaint && tryDrawBitmapGdiPlus(rPosAry, rSalBitmap)) - { - return; - } - - // fall back old stuff - ImplDrawBitmap(getHDC(), rPosAry, static_cast(rSalBitmap), - mbPrinter, - mbXORMode ? SRCINVERT : SRCCOPY ); + mpImpl->drawBitmap( rPosAry, rSalBitmap ); } void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, SalColor nTransparentColor ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - - const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); - - WinSalBitmap* pMask = new WinSalBitmap; - const Point aPoint; - const Size aSize( rSalBitmap.GetSize() ); - HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL ); - HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap ); - const BYTE cRed = SALCOLOR_RED( nTransparentColor ); - const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor ); - const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor ); - - if( rSalBitmap.ImplGethDDB() ) - { - HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() ); - COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); - - BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); - - SetBkColor( hSrcDC, aOldCol ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - } - else - { - WinSalBitmap* pTmpSalBmp = new WinSalBitmap; - - if( pTmpSalBmp->Create( rSalBitmap, this ) ) - { - HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() ); - COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); - - BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); - - SetBkColor( hSrcDC, aOldCol ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - } - - delete pTmpSalBmp; - } - - ImplReleaseCachedDC( CACHED_HDC_1 ); - - // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE ) - if( pMask->Create( hMaskBitmap, FALSE, FALSE ) ) - drawBitmap( rPosAry, rSalBitmap, *pMask ); - - delete pMask; + mpImpl->drawBitmap( rPosAry, rSSalBitmap, nTransparentColor ); } void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, const SalBitmap& rSTransparentBitmap ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - bool bTryDirectPaint(!mbPrinter && !mbXORMode); - - if(bTryDirectPaint) - { - // only paint direct when no scaling and no MapMode, else the - // more expensive conversions may be done for short-time Bitmap/BitmapEx - // used for buffering only - if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) - { - bTryDirectPaint = false; - } - } - - // try to draw using GdiPlus directly - if(bTryDirectPaint && drawAlphaBitmap(rPosAry, rSSalBitmap, rSTransparentBitmap)) - { - return; - } - - const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); - const WinSalBitmap& rTransparentBitmap = static_cast(rSTransparentBitmap); - - SalTwoRect aPosAry = rPosAry; - int nDstX = (int)aPosAry.mnDestX; - int nDstY = (int)aPosAry.mnDestY; - int nDstWidth = (int)aPosAry.mnDestWidth; - int nDstHeight = (int)aPosAry.mnDestHeight; - HDC hDC = getHDC(); - HBITMAP hMemBitmap = 0; - HBITMAP hMaskBitmap = 0; - - if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) ) - { - hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); - hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); - } - - HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap ); - HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap ); - - aPosAry.mnDestX = aPosAry.mnDestY = 0; - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY ); - - // WIN/WNT seems to have a minor problem mapping the correct color of the - // mask to the palette if we draw the DIB directly ==> draw DDB - if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 ) - { - WinSalBitmap aTmp; - - if( aTmp.Create( rTransparentBitmap, this ) ) - ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY ); - } - else - ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY ); - - // now MemDC contains background, MaskDC the transparency mask - - // #105055# Respect XOR mode - if( mbXORMode ) - { - ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); - // now MaskDC contains the bitmap area with black background - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT ); - // now MemDC contains background XORed bitmap area ontop - } - else - { - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND ); - // now MemDC contains background with masked-out bitmap area - ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); - // now MaskDC contains the bitmap area with black background - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT ); - // now MemDC contains background and bitmap merged together - } - // copy to output DC - BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY ); - - ImplReleaseCachedDC( CACHED_HDC_1 ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - - // hMemBitmap != 0 ==> hMaskBitmap != 0 - if( hMemBitmap ) - { - DeleteObject( hMemBitmap ); - DeleteObject( hMaskBitmap ); - } + mpImpl->drawBitmap( rPosAry, rSSalBitmap, rSTransparentBitmap ); } bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) { - if( mbPen || !mbBrush || mbXORMode ) - return false; // can only perform solid fills without XOR. - - HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 ); - SetPixel( hMemDC, (int)0, (int)0, mnBrushColor ); - - BLENDFUNCTION aFunc = { - AC_SRC_OVER, - 0, - sal::static_int_cast(255 - 255L*nTransparency/100), - 0 - }; - - // hMemDC contains a 1x1 bitmap of the right color - stretch-blit - // that to dest hdc - bool bRet = AlphaBlend( getHDC(), nX, nY, nWidth, nHeight, - hMemDC, 0,0,1,1, - aFunc ) == TRUE; - - ImplReleaseCachedDC( CACHED_HDC_1 ); - - return bRet; + return mpImpl->drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency ); } void WinSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, SalColor nMaskColor ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - - const WinSalBitmap& rSalBitmap = static_cast(rSSalBitmap); - - SalTwoRect aPosAry = rPosAry; - const BYTE cRed = SALCOLOR_RED( nMaskColor ); - const BYTE cGreen = SALCOLOR_GREEN( nMaskColor ); - const BYTE cBlue = SALCOLOR_BLUE( nMaskColor ); - HDC hDC = getHDC(); - HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) ); - HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush ); - - // WIN/WNT seems to have a minor problem mapping the correct color of the - // mask to the palette if we draw the DIB directly ==> draw DDB - if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 ) - { - WinSalBitmap aTmp; - - if( aTmp.Create( rSalBitmap, this ) ) - ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL ); - } - else - ImplDrawBitmap( hDC, aPosAry, rSalBitmap, FALSE, 0x00B8074AUL ); - - SelectBrush( hDC, hOldBrush ); - DeleteBrush( hMaskBrush ); + mpImpl->drawMask( rPosAry, rSSalBitmap, nMaskColor ); } SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) { - DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" ); - - WinSalBitmap* pSalBitmap = NULL; - - nDX = labs( nDX ); - nDY = labs( nDY ); - - HDC hDC = getHDC(); - HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); - HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap ); - bool bRet; - - bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE; - ImplReleaseCachedDC( CACHED_HDC_1 ); - - if( bRet ) - { - pSalBitmap = new WinSalBitmap; - - if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) ) - { - delete pSalBitmap; - pSalBitmap = NULL; - } - } - else - { - // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers) - DeleteBitmap( hBmpBitmap ); - } - - return pSalBitmap; + return mpImpl->getBitmap( nX, nY, nDX, nDY ); } SalColor WinSalGraphics::getPixel( long nX, long nY ) { - COLORREF aWinCol = ::GetPixel( getHDC(), (int) nX, (int) nY ); - - if ( CLR_INVALID == aWinCol ) - return MAKE_SALCOLOR( 0, 0, 0 ); - else - return MAKE_SALCOLOR( GetRValue( aWinCol ), - GetGValue( aWinCol ), - GetBValue( aWinCol ) ); + return mpImpl->getPixel( nX, nY ); } void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) { - if ( nFlags & SAL_INVERT_TRACKFRAME ) - { - HPEN hDotPen = CreatePen( PS_DOT, 0, 0 ); - HPEN hOldPen = SelectPen( getHDC(), hDotPen ); - HBRUSH hOldBrush = SelectBrush( getHDC(), GetStockBrush( NULL_BRUSH ) ); - int nOldROP = SetROP2( getHDC(), R2_NOT ); - - WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); - - SetROP2( getHDC(), nOldROP ); - SelectPen( getHDC(), hOldPen ); - SelectBrush( getHDC(), hOldBrush ); - DeletePen( hDotPen ); - } - else if ( nFlags & SAL_INVERT_50 ) - { - SalData* pSalData = GetSalData(); - if ( !pSalData->mh50Brush ) - { - if ( !pSalData->mh50Bmp ) - pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); - pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); - } - - COLORREF nOldTextColor = ::SetTextColor( getHDC(), 0 ); - HBRUSH hOldBrush = SelectBrush( getHDC(), pSalData->mh50Brush ); - PatBlt( getHDC(), nX, nY, nWidth, nHeight, PATINVERT ); - ::SetTextColor( getHDC(), nOldTextColor ); - SelectBrush( getHDC(), hOldBrush ); - } - else - { - RECT aRect; - aRect.left = (int)nX; - aRect.top = (int)nY; - aRect.right = (int)nX+nWidth; - aRect.bottom = (int)nY+nHeight; - ::InvertRect( getHDC(), &aRect ); - } + mpImpl->invert( nX, nY, nWidth, nHeight, nFlags ); } void WinSalGraphics::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) { - HPEN hPen; - HPEN hOldPen; - HBRUSH hBrush; - HBRUSH hOldBrush = 0; - COLORREF nOldTextColor RGB(0,0,0); - int nOldROP = SetROP2( getHDC(), R2_NOT ); - - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - hPen = CreatePen( PS_DOT, 0, 0 ); - else - { - - if ( nSalFlags & SAL_INVERT_50 ) - { - SalData* pSalData = GetSalData(); - if ( !pSalData->mh50Brush ) - { - if ( !pSalData->mh50Bmp ) - pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); - pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); - } - - hBrush = pSalData->mh50Brush; - } - else - hBrush = GetStockBrush( BLACK_BRUSH ); - - hPen = GetStockPen( NULL_PEN ); - nOldTextColor = ::SetTextColor( getHDC(), 0 ); - hOldBrush = SelectBrush( getHDC(), hBrush ); - } - hOldPen = SelectPen( getHDC(), hPen ); - - POINT* pWinPtAry; - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" ); - - pWinPtAry = (POINT*)pPtAry; - // for Windows 95 and its maximum number of points - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - { - if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - } - else - { - if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - } - - SetROP2( getHDC(), nOldROP ); - SelectPen( getHDC(), hOldPen ); - - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - DeletePen( hPen ); - else - { - ::SetTextColor( getHDC(), nOldTextColor ); - SelectBrush( getHDC(), hOldBrush ); - } + mpImpl->invert( nPoints, pPtAry, nSalFlags ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx index 1dc4f05a088a..65dbdd84acec 100644 --- a/vcl/win/source/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx @@ -25,195 +25,11 @@ #include #include -#if defined _MSC_VER -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#endif - -#if defined _MSC_VER -#pragma warning(push, 1) -#endif - -#ifdef __MINGW32__ -#ifdef GetObject -#undef GetObject -#endif -#define GetObject GetObjectA -#endif - -#include -#include -#include - -#ifdef __MINGW32__ -#ifdef GetObject -#undef GetObject -#endif -#endif - -#if defined _MSC_VER -#pragma warning(pop) -#endif - -#include - -void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) -{ - sal_uInt32 nCount(rPolygon.count()); - - if(nCount) - { - const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); - const bool bControls(rPolygon.areControlPointsUsed()); - basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); - - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - const sal_uInt32 nNextIndex((a + 1) % nCount); - const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); - - if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) - { - const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); - const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); - - Gdiplus::DllExports::GdipAddPathBezier(pPath, - aCurr.getX(), aCurr.getY(), - aCa.getX(), aCa.getY(), - aCb.getX(), aCb.getY(), - aNext.getX(), aNext.getY()); - } - else - { - Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); - } - - if(a + 1 < nEdgeCount) - { - aCurr = aNext; - - if(bNoLineJoin) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); - } - } - } - } -} - -void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) -{ - sal_uInt32 nCount(rPolygon.count()); - - if(nCount) - { - const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); - const bool bControls(rPolygon.areControlPointsUsed()); - basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); - - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - const sal_uInt32 nNextIndex((a + 1) % nCount); - const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); - - if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) - { - const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); - const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); - - Gdiplus::DllExports::GdipAddPathBezier( - pPath, - aCurr.getX(), aCurr.getY(), - aCa.getX(), aCa.getY(), - aCb.getX(), aCb.getY(), - aNext.getX(), aNext.getY()); - } - else - { - Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); - } - - if(a + 1 < nEdgeCount) - { - aCurr = aNext; - - if(bNoLineJoin) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); - } - } - } - } -} +#include "gdiimpl.hxx" bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) { - const sal_uInt32 nCount(rPolyPolygon.count()); - - if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) - { - Gdiplus::GpGraphics *pGraphics = NULL; - Gdiplus::DllExports::GdipCreateFromHDC(getHDC(), &pGraphics); - const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0)); - Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor)); - Gdiplus::GpSolidFill *pTestBrush; - Gdiplus::DllExports::GdipCreateSolidFill(aTestColor.GetValue(), &pTestBrush); - Gdiplus::GpPath *pPath = NULL; - Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); - - for(sal_uInt32 a(0); a < nCount; a++) - { - if(0 != a) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); // #i101491# not needed for first run - } - - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false); - Gdiplus::DllExports::GdipClosePathFigure(pPath); - } - - if(getAntiAliasB2DDraw()) - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); - } - else - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); - } - - if(mbPrinter) - { - // #i121591# - // Normally GdiPlus should not be used for printing at all since printers cannot - // print transparent filled polygon geometry and normally this does not happen - // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation - // and no transparent parts should remain for printing. But this can be overridden - // by the user and thus happens. This call can only come (currently) from - // OutputDevice::DrawTransparent, see comments there with the same TaskID. - // If it is used, the mapping for the printer is wrong and needs to be corrected. I - // checked that there is *no* transformation set and estimated that a stable factor - // dependent of the printer's DPI is used. Create and set a transformation here to - // correct this. - Gdiplus::REAL aDpiX; - Gdiplus::DllExports::GdipGetDpiX(pGraphics, &aDpiX); - Gdiplus::REAL aDpiY; - Gdiplus::DllExports::GdipGetDpiY(pGraphics, &aDpiY); - - Gdiplus::DllExports::GdipResetWorldTransform(pGraphics); - Gdiplus::DllExports::GdipScaleWorldTransform(pGraphics, Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend); - } - - Gdiplus::DllExports::GdipFillPath(pGraphics, pTestBrush, pPath); - - Gdiplus::DllExports::GdipDeletePath(pPath); - Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); - } - - return true; + return mpImpl->drawPolyPolygon( rPolyPolygon, fTransparency ); } bool WinSalGraphics::drawPolyLine( @@ -223,199 +39,8 @@ bool WinSalGraphics::drawPolyLine( basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { - const sal_uInt32 nCount(rPolygon.count()); - - if(mbPen && nCount) - { - Gdiplus::GpGraphics *pGraphics = NULL; - Gdiplus::DllExports::GdipCreateFromHDC(getHDC(), &pGraphics); - const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) ); - Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); - Gdiplus::GpPen *pTestPen = NULL; - Gdiplus::DllExports::GdipCreatePen1(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX()), Gdiplus::UnitWorld, &pTestPen); - Gdiplus::GpPath *pPath; - Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); - bool bNoLineJoin(false); - - switch(eLineJoin) - { - default : // basegfx::B2DLINEJOIN_NONE : - { - if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) - { - bNoLineJoin = true; - } - break; - } - case basegfx::B2DLINEJOIN_BEVEL : - { - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinBevel); - break; - } - case basegfx::B2DLINEJOIN_MIDDLE : - case basegfx::B2DLINEJOIN_MITER : - { - const Gdiplus::REAL aMiterLimit(15.0); - Gdiplus::DllExports::GdipSetPenMiterLimit(pTestPen, aMiterLimit); - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinMiter); - break; - } - case basegfx::B2DLINEJOIN_ROUND : - { - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinRound); - break; - } - } - - switch(eLineCap) - { - default: /*com::sun::star::drawing::LineCap_BUTT*/ - { - // nothing to do - break; - } - case com::sun::star::drawing::LineCap_ROUND: - { - Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapRound); - Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapRound); - break; - } - case com::sun::star::drawing::LineCap_SQUARE: - { - Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapSquare); - Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapSquare); - break; - } - } - - if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) - { - impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath, rPolygon, bNoLineJoin); - } - else - { - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin); - } - - if(rPolygon.isClosed() && !bNoLineJoin) - { - // #i101491# needed to create the correct line joins - Gdiplus::DllExports::GdipClosePathFigure(pPath); - } - - if(getAntiAliasB2DDraw()) - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); - } - else - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); - } - - Gdiplus::DllExports::GdipDrawPath(pGraphics, pTestPen, pPath); - - Gdiplus::DllExports::GdipDeletePath(pPath); - Gdiplus::DllExports::GdipDeletePen(pTestPen); - Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); - } - - return true; -} - -void paintToGdiPlus( - Gdiplus::Graphics& rGraphics, - const SalTwoRect& rTR, - Gdiplus::Bitmap& rBitmap) -{ - // only parts of source are used - Gdiplus::PointF aDestPoints[3]; - Gdiplus::ImageAttributes aAttributes; - - // define target region as paralellogram - aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); - aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); - - aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); - - rGraphics.DrawImage( - &rBitmap, - aDestPoints, - 3, - Gdiplus::REAL(rTR.mnSrcX), - Gdiplus::REAL(rTR.mnSrcY), - Gdiplus::REAL(rTR.mnSrcWidth), - Gdiplus::REAL(rTR.mnSrcHeight), - Gdiplus::UnitPixel, - &aAttributes, - 0, - 0); -} - -void setInterpolationMode( - Gdiplus::Graphics& rGraphics, - const long& rSrcWidth, - const long& rDestWidth, - const long& rSrcHeight, - const long& rDestHeight) -{ - const bool bSameWidth(rSrcWidth == rDestWidth); - const bool bSameHeight(rSrcHeight == rDestHeight); - - if(bSameWidth && bSameHeight) - { -#ifdef __MINGW32__ - //Gdiplus::InterpolationModeInvalid is missing on mingw - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); -#else - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid); -#endif - } - else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight) - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); - } - else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight) - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); - } - else - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); - } -} - -bool WinSalGraphics::tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap) -{ - if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) - { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); - - if(aARGB.get()) - { - Gdiplus::Graphics aGraphics(getHDC()); - - setInterpolationMode( - aGraphics, - rTR.mnSrcWidth, - rTR.mnDestWidth, - rTR.mnSrcHeight, - rTR.mnDestHeight); - - paintToGdiPlus( - aGraphics, - rTR, - *aARGB.get()); - - return true; - } - } - - return false; + return mpImpl->drawPolyLine(rPolygon, fTransparency, rLineWidths, + eLineJoin, eLineCap); } bool WinSalGraphics::drawAlphaBitmap( @@ -423,33 +48,7 @@ bool WinSalGraphics::drawAlphaBitmap( const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp) { - if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) - { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); - const WinSalBitmap& rSalAlpha = static_cast< const WinSalBitmap& >(rAlphaBmp); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(&rSalAlpha)); - - if(aARGB.get()) - { - Gdiplus::Graphics aGraphics(getHDC()); - - setInterpolationMode( - aGraphics, - rTR.mnSrcWidth, - rTR.mnDestWidth, - rTR.mnSrcHeight, - rTR.mnDestHeight); - - paintToGdiPlus( - aGraphics, - rTR, - *aARGB.get()); - - return true; - } - } - - return false; + return mpImpl->drawAlphaBitmap(rTR, rSrcBitmap, rAlphaBmp); } bool WinSalGraphics::drawTransformedBitmap( @@ -459,62 +58,8 @@ bool WinSalGraphics::drawTransformedBitmap( const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap) { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); - const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); - - if(aARGB.get()) - { - const long nSrcWidth(aARGB->GetWidth()); - const long nSrcHeight(aARGB->GetHeight()); - - if(nSrcWidth && nSrcHeight) - { - const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); - const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); - - if(nDestWidth && nDestHeight) - { - Gdiplus::Graphics aGraphics(getHDC()); - Gdiplus::PointF aDestPoints[3]; - Gdiplus::ImageAttributes aAttributes; - - setInterpolationMode( - aGraphics, - nSrcWidth, - nDestWidth, - nSrcHeight, - nDestHeight); - - // this mode is only capable of drawing the whole bitmap to a paralellogram - aDestPoints[0].X = Gdiplus::REAL(rNull.getX()); - aDestPoints[0].Y = Gdiplus::REAL(rNull.getY()); - aDestPoints[1].X = Gdiplus::REAL(rX.getX()); - aDestPoints[1].Y = Gdiplus::REAL(rX.getY()); - aDestPoints[2].X = Gdiplus::REAL(rY.getX()); - aDestPoints[2].Y = Gdiplus::REAL(rY.getY()); - - aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); - - aGraphics.DrawImage( - aARGB.get(), - aDestPoints, - 3, - Gdiplus::REAL(0.0), - Gdiplus::REAL(0.0), - Gdiplus::REAL(nSrcWidth), - Gdiplus::REAL(nSrcHeight), - Gdiplus::UnitPixel, - &aAttributes, - 0, - 0); - } - } - - return true; - } - - return false; + return mpImpl->drawTransformedBitmap(rNull, rX, rY, + rSourceBitmap, pAlphaBitmap); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit