1145 lines
36 KiB
C++
1145 lines
36 KiB
C++
/* -*- 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 <string.h>
|
|
#include <svsys.h>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <tools/poly.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <basegfx/polygon/b2dpolypolygontools.hxx>
|
|
#include <comphelper/windowserrorstring.hxx>
|
|
#include <win/wincomp.hxx>
|
|
#include <win/saldata.hxx>
|
|
#include <win/salgdi.h>
|
|
#include <win/salframe.h>
|
|
#include <win/salvd.h>
|
|
#include <win/winlayout.hxx>
|
|
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
|
|
|
#include <salgdiimpl.hxx>
|
|
#include "gdiimpl.hxx"
|
|
|
|
#include <config_features.h>
|
|
#include <vcl/skia/SkiaHelper.hxx>
|
|
#if HAVE_FEATURE_SKIA
|
|
#include <skia/win/gdiimpl.hxx>
|
|
#endif
|
|
|
|
|
|
#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
|
|
|
|
namespace
|
|
{
|
|
|
|
struct SysColorEntry
|
|
{
|
|
DWORD nRGB;
|
|
SysColorEntry* pNext;
|
|
};
|
|
|
|
SysColorEntry* pFirstSysColor = nullptr;
|
|
SysColorEntry* pActSysColor = nullptr;
|
|
|
|
void DeleteSysColorList()
|
|
{
|
|
SysColorEntry* pEntry = pFirstSysColor;
|
|
pActSysColor = pFirstSysColor = nullptr;
|
|
|
|
while( pEntry )
|
|
{
|
|
SysColorEntry* pTmp = pEntry->pNext;
|
|
delete pEntry;
|
|
pEntry = pTmp;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Blue7
|
|
static PALETTEENTRY aImplExtraColor1 =
|
|
{
|
|
0, 184, 255, 0
|
|
};
|
|
|
|
static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] =
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0x80, 0 },
|
|
{ 0, 0x80, 0, 0 },
|
|
{ 0, 0x80, 0x80, 0 },
|
|
{ 0x80, 0, 0, 0 },
|
|
{ 0x80, 0, 0x80, 0 },
|
|
{ 0x80, 0x80, 0, 0 },
|
|
{ 0x80, 0x80, 0x80, 0 },
|
|
{ 0xC0, 0xC0, 0xC0, 0 },
|
|
{ 0, 0, 0xFF, 0 },
|
|
{ 0, 0xFF, 0, 0 },
|
|
{ 0, 0xFF, 0xFF, 0 },
|
|
{ 0xFF, 0, 0, 0 },
|
|
{ 0xFF, 0, 0xFF, 0 },
|
|
{ 0xFF, 0xFF, 0, 0 },
|
|
{ 0xFF, 0xFF, 0xFF, 0 }
|
|
};
|
|
|
|
// we must create pens with 1-pixel width; otherwise the S3-graphics card
|
|
// map has many paint problems when drawing polygons/polyLines and a
|
|
// complex is set
|
|
#define GSL_PEN_WIDTH 1
|
|
|
|
void ImplInitSalGDI()
|
|
{
|
|
SalData* pSalData = GetSalData();
|
|
|
|
pSalData->mbResourcesAlreadyFreed = false;
|
|
|
|
// init stock brushes
|
|
pSalData->maStockPenColorAry[0] = PALETTERGB( 0, 0, 0 );
|
|
pSalData->maStockPenColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
|
|
pSalData->maStockPenColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
|
|
pSalData->maStockPenColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
|
|
pSalData->mhStockPenAry[0] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[0] );
|
|
pSalData->mhStockPenAry[1] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[1] );
|
|
pSalData->mhStockPenAry[2] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[2] );
|
|
pSalData->mhStockPenAry[3] = CreatePen( PS_SOLID, GSL_PEN_WIDTH, pSalData->maStockPenColorAry[3] );
|
|
pSalData->mnStockPenCount = 4;
|
|
|
|
pSalData->maStockBrushColorAry[0] = PALETTERGB( 0, 0, 0 );
|
|
pSalData->maStockBrushColorAry[1] = PALETTERGB( 0xFF, 0xFF, 0xFF );
|
|
pSalData->maStockBrushColorAry[2] = PALETTERGB( 0xC0, 0xC0, 0xC0 );
|
|
pSalData->maStockBrushColorAry[3] = PALETTERGB( 0x80, 0x80, 0x80 );
|
|
pSalData->mhStockBrushAry[0] = CreateSolidBrush( pSalData->maStockBrushColorAry[0] );
|
|
pSalData->mhStockBrushAry[1] = CreateSolidBrush( pSalData->maStockBrushColorAry[1] );
|
|
pSalData->mhStockBrushAry[2] = CreateSolidBrush( pSalData->maStockBrushColorAry[2] );
|
|
pSalData->mhStockBrushAry[3] = CreateSolidBrush( pSalData->maStockBrushColorAry[3] );
|
|
pSalData->mnStockBrushCount = 4;
|
|
|
|
// initialize temporary font lists
|
|
pSalData->mpSharedTempFontItem = nullptr;
|
|
pSalData->mpOtherTempFontItem = nullptr;
|
|
|
|
// support palettes for 256 color displays
|
|
HDC hDC = GetDC( nullptr );
|
|
int nBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
|
|
int nPlanes = GetDeviceCaps( hDC, PLANES );
|
|
int nRasterCaps = GetDeviceCaps( hDC, RASTERCAPS );
|
|
int nBitCount = nBitsPixel * nPlanes;
|
|
|
|
if ( (nBitCount > 8) && (nBitCount < 24) )
|
|
{
|
|
// test if we have to dither
|
|
HDC hMemDC = ::CreateCompatibleDC( hDC );
|
|
HBITMAP hMemBmp = ::CreateCompatibleBitmap( hDC, 8, 8 );
|
|
HBITMAP hBmpOld = static_cast<HBITMAP>(::SelectObject( hMemDC, hMemBmp ));
|
|
HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
|
|
HBRUSH hBrushOld = static_cast<HBRUSH>(::SelectObject( hMemDC, hMemBrush ));
|
|
bool bDither16 = true;
|
|
|
|
::PatBlt( hMemDC, 0, 0, 8, 8, PATCOPY );
|
|
const COLORREF aCol( ::GetPixel( hMemDC, 0, 0 ) );
|
|
|
|
for( int nY = 0; ( nY < 8 ) && bDither16; nY++ )
|
|
for( int nX = 0; ( nX < 8 ) && bDither16; nX++ )
|
|
if( ::GetPixel( hMemDC, nX, nY ) != aCol )
|
|
bDither16 = false;
|
|
|
|
::SelectObject( hMemDC, hBrushOld );
|
|
::DeleteObject( hMemBrush );
|
|
::SelectObject( hMemDC, hBmpOld );
|
|
::DeleteObject( hMemBmp );
|
|
::DeleteDC( hMemDC );
|
|
|
|
if( bDither16 )
|
|
{
|
|
// create DIBPattern for 16Bit dithering
|
|
tools::Long n;
|
|
|
|
pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
|
|
pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
|
|
pSalData->mpDitherDiff.reset(new tools::Long[ 256 ]);
|
|
pSalData->mpDitherLow.reset(new BYTE[ 256 ]);
|
|
pSalData->mpDitherHigh.reset(new BYTE[ 256 ]);
|
|
pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
|
|
memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
|
|
|
|
BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
|
|
|
|
pBIH->biSize = sizeof( BITMAPINFOHEADER );
|
|
pBIH->biWidth = 8;
|
|
pBIH->biHeight = 8;
|
|
pBIH->biPlanes = 1;
|
|
pBIH->biBitCount = 24;
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n & 248 );
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 8, 255 ));
|
|
}
|
|
}
|
|
else if ( (nRasterCaps & RC_PALETTE) && (nBitCount == 8) )
|
|
{
|
|
BYTE nRed, nGreen, nBlue;
|
|
BYTE nR, nG, nB;
|
|
PALETTEENTRY* pPalEntry;
|
|
LOGPALETTE* pLogPal;
|
|
const sal_uInt16 nDitherPalCount = DITHER_PAL_COUNT;
|
|
sal_uLong nTotalCount = DITHER_MAX_SYSCOLOR + nDitherPalCount + DITHER_EXTRA_COLORS;
|
|
|
|
// create logical palette
|
|
pLogPal = reinterpret_cast<LOGPALETTE*>(new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ]);
|
|
pLogPal->palVersion = 0x0300;
|
|
pLogPal->palNumEntries = static_cast<sal_uInt16>(nTotalCount);
|
|
pPalEntry = pLogPal->palPalEntry;
|
|
|
|
// Standard colors
|
|
memcpy( pPalEntry, aImplSalSysPalEntryAry, DITHER_MAX_SYSCOLOR * sizeof( PALETTEENTRY ) );
|
|
pPalEntry += DITHER_MAX_SYSCOLOR;
|
|
|
|
// own palette (6/6/6)
|
|
for( nB=0, nBlue=0; nB < DITHER_PAL_STEPS; nB++, nBlue += DITHER_PAL_DELTA )
|
|
{
|
|
for( nG=0, nGreen=0; nG < DITHER_PAL_STEPS; nG++, nGreen += DITHER_PAL_DELTA )
|
|
{
|
|
for( nR=0, nRed=0; nR < DITHER_PAL_STEPS; nR++, nRed += DITHER_PAL_DELTA )
|
|
{
|
|
pPalEntry->peRed = nRed;
|
|
pPalEntry->peGreen = nGreen;
|
|
pPalEntry->peBlue = nBlue;
|
|
pPalEntry->peFlags = 0;
|
|
pPalEntry++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// insert special 'Blue' as standard drawing color
|
|
*pPalEntry++ = aImplExtraColor1;
|
|
|
|
// create palette
|
|
pSalData->mhDitherPal = CreatePalette( pLogPal );
|
|
delete[] reinterpret_cast<char*>(pLogPal);
|
|
|
|
if( pSalData->mhDitherPal )
|
|
{
|
|
// create DIBPattern for 8Bit dithering
|
|
tools::Long const nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
|
|
tools::Long n;
|
|
|
|
pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
|
|
pSalData->mpDitherDIB = static_cast<BYTE*>(GlobalLock( pSalData->mhDitherDIB ));
|
|
pSalData->mpDitherDiff.reset(new tools::Long[ 256 ]);
|
|
pSalData->mpDitherLow.reset(new BYTE[ 256 ]);
|
|
pSalData->mpDitherHigh.reset(new BYTE[ 256 ]);
|
|
pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
|
|
memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
|
|
|
|
BITMAPINFOHEADER* pBIH = reinterpret_cast<BITMAPINFOHEADER*>(pSalData->mpDitherDIB);
|
|
short* pColors = reinterpret_cast<short*>( pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) );
|
|
|
|
pBIH->biSize = sizeof( BITMAPINFOHEADER );
|
|
pBIH->biWidth = 8;
|
|
pBIH->biHeight = 8;
|
|
pBIH->biPlanes = 1;
|
|
pBIH->biBitCount = 8;
|
|
|
|
for( n = 0; n < nDitherPalCount; n++ )
|
|
pColors[ n ] = static_cast<short>( n + DITHER_MAX_SYSCOLOR );
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherDiff[ n ] = n % 51;
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherLow[ n ] = static_cast<BYTE>( n / 51 );
|
|
|
|
for( n = 0; n < 256; n++ )
|
|
pSalData->mpDitherHigh[ n ] = static_cast<BYTE>(std::min( pSalData->mpDitherLow[ n ] + 1, 5 ));
|
|
}
|
|
|
|
// get system color entries
|
|
ImplUpdateSysColorEntries();
|
|
}
|
|
|
|
ReleaseDC( nullptr, hDC );
|
|
}
|
|
|
|
void ImplFreeSalGDI()
|
|
{
|
|
SalData* pSalData = GetSalData();
|
|
|
|
if (pSalData->mbResourcesAlreadyFreed)
|
|
return;
|
|
|
|
// destroy stock objects
|
|
int i;
|
|
for ( i = 0; i < pSalData->mnStockPenCount; i++ )
|
|
DeletePen( pSalData->mhStockPenAry[i] );
|
|
for ( i = 0; i < pSalData->mnStockBrushCount; i++ )
|
|
DeleteBrush( pSalData->mhStockBrushAry[i] );
|
|
|
|
// delete 50% Brush
|
|
if ( pSalData->mh50Brush )
|
|
{
|
|
DeleteBrush( pSalData->mh50Brush );
|
|
pSalData->mh50Brush = nullptr;
|
|
}
|
|
|
|
// delete 50% Bitmap
|
|
if ( pSalData->mh50Bmp )
|
|
{
|
|
DeleteBitmap( pSalData->mh50Bmp );
|
|
pSalData->mh50Bmp = nullptr;
|
|
}
|
|
|
|
ImplClearHDCCache( pSalData );
|
|
|
|
// delete Ditherpalette, if existing
|
|
if ( pSalData->mhDitherPal )
|
|
{
|
|
DeleteObject( pSalData->mhDitherPal );
|
|
pSalData->mhDitherPal = nullptr;
|
|
}
|
|
|
|
// delete buffers for dithering DIB patterns, if necessary
|
|
if ( pSalData->mhDitherDIB )
|
|
{
|
|
GlobalUnlock( pSalData->mhDitherDIB );
|
|
GlobalFree( pSalData->mhDitherDIB );
|
|
pSalData->mhDitherDIB = nullptr;
|
|
pSalData->mpDitherDiff.reset();
|
|
pSalData->mpDitherLow.reset();
|
|
pSalData->mpDitherHigh.reset();
|
|
}
|
|
|
|
DeleteSysColorList();
|
|
|
|
// delete icon cache
|
|
SalIcon* pIcon = pSalData->mpFirstIcon;
|
|
pSalData->mpFirstIcon = nullptr;
|
|
while( pIcon )
|
|
{
|
|
SalIcon* pTmp = pIcon->pNext;
|
|
DestroyIcon( pIcon->hIcon );
|
|
DestroyIcon( pIcon->hSmallIcon );
|
|
delete pIcon;
|
|
pIcon = pTmp;
|
|
}
|
|
|
|
// delete temporary font list
|
|
ImplReleaseTempFonts(*pSalData, true);
|
|
|
|
pSalData->mbResourcesAlreadyFreed = true;
|
|
}
|
|
|
|
int ImplIsSysColorEntry( Color nColor )
|
|
{
|
|
SysColorEntry* pEntry = pFirstSysColor;
|
|
const DWORD nTestRGB = static_cast<DWORD>(RGB( nColor.GetRed(),
|
|
nColor.GetGreen(),
|
|
nColor.GetBlue() ));
|
|
|
|
while ( pEntry )
|
|
{
|
|
if ( pEntry->nRGB == nTestRGB )
|
|
return TRUE;
|
|
pEntry = pEntry->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue )
|
|
{
|
|
// dither color?
|
|
if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) )
|
|
return TRUE;
|
|
|
|
PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry;
|
|
|
|
// standard palette color?
|
|
for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ )
|
|
{
|
|
if( pPalEntry->peRed == 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;
|
|
}
|
|
|
|
static void ImplInsertSysColorEntry( int nSysIndex )
|
|
{
|
|
const DWORD nRGB = GetSysColor( nSysIndex );
|
|
|
|
if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
|
|
{
|
|
if ( !pFirstSysColor )
|
|
{
|
|
pActSysColor = pFirstSysColor = new SysColorEntry;
|
|
pFirstSysColor->nRGB = nRGB;
|
|
pFirstSysColor->pNext = nullptr;
|
|
}
|
|
else
|
|
{
|
|
pActSysColor = pActSysColor->pNext = new SysColorEntry;
|
|
pActSysColor->nRGB = nRGB;
|
|
pActSysColor->pNext = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImplUpdateSysColorEntries()
|
|
{
|
|
DeleteSysColorList();
|
|
|
|
// create new sys color list
|
|
ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
|
|
ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
|
|
ImplInsertSysColorEntry( COLOR_GRADIENTACTIVECAPTION );
|
|
ImplInsertSysColorEntry( COLOR_GRADIENTINACTIVECAPTION );
|
|
ImplInsertSysColorEntry( COLOR_3DFACE );
|
|
ImplInsertSysColorEntry( COLOR_3DHILIGHT );
|
|
ImplInsertSysColorEntry( COLOR_3DLIGHT );
|
|
ImplInsertSysColorEntry( COLOR_3DSHADOW );
|
|
ImplInsertSysColorEntry( COLOR_3DDKSHADOW );
|
|
ImplInsertSysColorEntry( COLOR_INFOBK );
|
|
ImplInsertSysColorEntry( COLOR_INFOTEXT );
|
|
ImplInsertSysColorEntry( COLOR_BTNTEXT );
|
|
ImplInsertSysColorEntry( COLOR_WINDOW );
|
|
ImplInsertSysColorEntry( COLOR_WINDOWTEXT );
|
|
ImplInsertSysColorEntry( COLOR_HIGHLIGHT );
|
|
ImplInsertSysColorEntry( COLOR_HIGHLIGHTTEXT );
|
|
ImplInsertSysColorEntry( COLOR_MENU );
|
|
ImplInsertSysColorEntry( COLOR_MENUTEXT );
|
|
ImplInsertSysColorEntry( COLOR_ACTIVECAPTION );
|
|
ImplInsertSysColorEntry( COLOR_CAPTIONTEXT );
|
|
ImplInsertSysColorEntry( COLOR_INACTIVECAPTION );
|
|
ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT );
|
|
}
|
|
|
|
void WinSalGraphics::InitGraphics()
|
|
{
|
|
if (!getHDC())
|
|
return;
|
|
|
|
// calculate the minimal line width for the printer
|
|
if ( isPrinter() )
|
|
{
|
|
int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
|
|
if ( nDPIX <= 300 )
|
|
mnPenWidth = 0;
|
|
else
|
|
mnPenWidth = nDPIX/300;
|
|
}
|
|
|
|
::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
|
|
::SetBkMode( getHDC(), TRANSPARENT );
|
|
::SetROP2( getHDC(), R2_COPYPEN );
|
|
}
|
|
|
|
void WinSalGraphics::DeInitGraphics()
|
|
{
|
|
if (!getHDC())
|
|
return;
|
|
|
|
// clear clip region
|
|
SelectClipRgn( getHDC(), nullptr );
|
|
// select default objects
|
|
if ( mhDefPen )
|
|
{
|
|
SelectPen( getHDC(), mhDefPen );
|
|
mhDefPen = nullptr;
|
|
}
|
|
if ( mhDefBrush )
|
|
{
|
|
SelectBrush( getHDC(), mhDefBrush );
|
|
mhDefBrush = nullptr;
|
|
}
|
|
if ( mhDefFont )
|
|
{
|
|
SelectFont( getHDC(), mhDefFont );
|
|
mhDefFont = nullptr;
|
|
}
|
|
setPalette(nullptr);
|
|
|
|
mpImpl->DeInit();
|
|
}
|
|
|
|
void WinSalGraphics::setHDC(HDC aNew)
|
|
{
|
|
DeInitGraphics();
|
|
mhLocalDC = aNew;
|
|
InitGraphics();
|
|
}
|
|
|
|
HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
|
|
{
|
|
SalData* pSalData = GetSalData();
|
|
HDCCache* pC = &pSalData->maHDCCache[ nID ];
|
|
|
|
if( !pC->mhDC )
|
|
{
|
|
HDC hDC = GetDC( nullptr );
|
|
|
|
// create new DC with DefaultBitmap
|
|
pC->mhDC = CreateCompatibleDC( hDC );
|
|
|
|
if( pSalData->mhDitherPal )
|
|
{
|
|
pC->mhDefPal = SelectPalette( pC->mhDC, pSalData->mhDitherPal, TRUE );
|
|
RealizePalette( pC->mhDC );
|
|
}
|
|
|
|
pC->mhSelBmp = CreateCompatibleBitmap( hDC, CACHED_HDC_DEFEXT, CACHED_HDC_DEFEXT );
|
|
pC->mhDefBmp = static_cast<HBITMAP>(SelectObject( pC->mhDC, pC->mhSelBmp ));
|
|
|
|
ReleaseDC( nullptr, hDC );
|
|
}
|
|
|
|
if ( hBmp )
|
|
SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
|
|
else
|
|
pC->mhActBmp = nullptr;
|
|
|
|
return pC->mhDC;
|
|
}
|
|
|
|
void ImplReleaseCachedDC( sal_uLong nID )
|
|
{
|
|
SalData* pSalData = GetSalData();
|
|
HDCCache* pC = &pSalData->maHDCCache[ nID ];
|
|
|
|
if ( pC->mhActBmp )
|
|
SelectObject( pC->mhDC, pC->mhSelBmp );
|
|
}
|
|
|
|
void ImplClearHDCCache( SalData* pData )
|
|
{
|
|
for( sal_uLong i = 0; i < CACHESIZE_HDC; i++ )
|
|
{
|
|
HDCCache* pC = &pData->maHDCCache[ i ];
|
|
|
|
if( pC->mhDC )
|
|
{
|
|
SelectObject( pC->mhDC, pC->mhDefBmp );
|
|
|
|
if( pC->mhDefPal )
|
|
SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
|
|
|
|
DeleteDC( pC->mhDC );
|
|
DeleteObject( pC->mhSelBmp );
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr< CompatibleDC > CompatibleDC::create(SalGraphics &rGraphics, int x, int y, int width, int height)
|
|
{
|
|
#if HAVE_FEATURE_SKIA
|
|
if (SkiaHelper::isVCLSkiaEnabled())
|
|
return std::make_unique< SkiaCompatibleDC >( rGraphics, x, y, width, height );
|
|
#endif
|
|
return std::unique_ptr< CompatibleDC >( new CompatibleDC( rGraphics, x, y, width, height ));
|
|
}
|
|
|
|
CompatibleDC::CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable)
|
|
: mhBitmap(nullptr)
|
|
, mpData(nullptr)
|
|
, maRects(0, 0, width, height, x, y, width, height)
|
|
, mpImpl(nullptr)
|
|
{
|
|
WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
|
|
|
|
if( disable )
|
|
{
|
|
// we avoid the OpenGL drawing, instead we draw directly to the DC
|
|
mhCompatibleDC = rWinGraphics.getHDC();
|
|
return;
|
|
}
|
|
|
|
mpImpl = rWinGraphics.getWinSalGraphicsImplBase();
|
|
mhCompatibleDC = CreateCompatibleDC(rWinGraphics.getHDC());
|
|
|
|
// move the origin so that we always paint at 0,0 - to keep the bitmap
|
|
// small
|
|
OffsetViewportOrgEx(mhCompatibleDC, -x, -y, nullptr);
|
|
|
|
mhBitmap = WinSalVirtualDevice::ImplCreateVirDevBitmap(mhCompatibleDC, width, height, 32, reinterpret_cast<void **>(&mpData));
|
|
|
|
mhOrigBitmap = static_cast<HBITMAP>(SelectObject(mhCompatibleDC, mhBitmap));
|
|
}
|
|
|
|
CompatibleDC::~CompatibleDC()
|
|
{
|
|
if (mpImpl)
|
|
{
|
|
SelectObject(mhCompatibleDC, mhOrigBitmap);
|
|
DeleteObject(mhBitmap);
|
|
DeleteDC(mhCompatibleDC);
|
|
}
|
|
}
|
|
|
|
void CompatibleDC::fill(sal_uInt32 color)
|
|
{
|
|
if (!mpData)
|
|
return;
|
|
|
|
sal_uInt32 *p = mpData;
|
|
for (int i = maRects.mnSrcWidth * maRects.mnSrcHeight; i > 0; --i)
|
|
*p++ = color;
|
|
}
|
|
|
|
WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, [[maybe_unused]] SalGeometryProvider *pProvider):
|
|
mhLocalDC(nullptr),
|
|
mbPrinter(eType == WinSalGraphics::PRINTER),
|
|
mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE),
|
|
mbWindow(eType == WinSalGraphics::WINDOW),
|
|
mbScreen(bScreen),
|
|
mhWnd(hWnd),
|
|
mhRegion(nullptr),
|
|
mhDefPen(nullptr),
|
|
mhDefBrush(nullptr),
|
|
mhDefFont(nullptr),
|
|
mhDefPal(nullptr),
|
|
mpStdClipRgnData(nullptr),
|
|
mnPenWidth(GSL_PEN_WIDTH)
|
|
{
|
|
#if HAVE_FEATURE_SKIA
|
|
if (SkiaHelper::isVCLSkiaEnabled() && !mbPrinter)
|
|
{
|
|
auto const impl = new WinSkiaSalGraphicsImpl(*this, pProvider);
|
|
mpImpl.reset(impl);
|
|
mWinSalGraphicsImplBase = impl;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
auto const impl = new WinSalGraphicsImpl(*this);
|
|
mpImpl.reset(impl);
|
|
mWinSalGraphicsImplBase = impl;
|
|
}
|
|
}
|
|
|
|
WinSalGraphics::~WinSalGraphics()
|
|
{
|
|
// free obsolete GDI objects
|
|
ReleaseFonts();
|
|
|
|
if ( mhRegion )
|
|
{
|
|
DeleteRegion( mhRegion );
|
|
mhRegion = nullptr;
|
|
}
|
|
|
|
// delete cache data
|
|
delete [] reinterpret_cast<BYTE*>(mpStdClipRgnData);
|
|
|
|
setHDC(nullptr);
|
|
}
|
|
|
|
SalGraphicsImpl* WinSalGraphics::GetImpl() const
|
|
{
|
|
return mpImpl.get();
|
|
}
|
|
|
|
bool WinSalGraphics::isPrinter() const
|
|
{
|
|
return mbPrinter;
|
|
}
|
|
|
|
bool WinSalGraphics::isVirtualDevice() const
|
|
{
|
|
return mbVirDev;
|
|
}
|
|
|
|
bool WinSalGraphics::isWindow() const
|
|
{
|
|
return mbWindow;
|
|
}
|
|
|
|
bool WinSalGraphics::isScreen() const
|
|
{
|
|
return mbScreen;
|
|
}
|
|
|
|
HWND WinSalGraphics::gethWnd()
|
|
{
|
|
return mhWnd;
|
|
}
|
|
|
|
void WinSalGraphics::setHWND(HWND hWnd)
|
|
{
|
|
mhWnd = hWnd;
|
|
}
|
|
|
|
HPALETTE WinSalGraphics::getDefPal() const
|
|
{
|
|
assert(getHDC() || !mhDefPal);
|
|
return mhDefPal;
|
|
}
|
|
|
|
UINT WinSalGraphics::setPalette(HPALETTE hNewPal, BOOL bForceBkgd)
|
|
{
|
|
UINT res = GDI_ERROR;
|
|
|
|
if (!getHDC())
|
|
{
|
|
assert(!mhDefPal);
|
|
return res;
|
|
}
|
|
|
|
if (hNewPal)
|
|
{
|
|
HPALETTE hOldPal = SelectPalette(getHDC(), hNewPal, bForceBkgd);
|
|
if (hOldPal)
|
|
{
|
|
if (!mhDefPal)
|
|
mhDefPal = hOldPal;
|
|
res = RealizePalette(getHDC());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res = 0;
|
|
if (mhDefPal)
|
|
{
|
|
SelectPalette(getHDC(), mhDefPal, bForceBkgd);
|
|
mhDefPal = nullptr;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
HRGN WinSalGraphics::getRegion() const
|
|
{
|
|
return mhRegion;
|
|
}
|
|
|
|
void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY )
|
|
{
|
|
rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX );
|
|
rDPIY = GetDeviceCaps( getHDC(), LOGPIXELSY );
|
|
|
|
// #111139# this fixes the symptom of div by zero on startup
|
|
// however, printing will fail most likely as communication with
|
|
// the printer seems not to work in this case
|
|
if( !rDPIX || !rDPIY )
|
|
rDPIX = rDPIY = 600;
|
|
}
|
|
|
|
// static
|
|
IDWriteFactory* WinSalGraphics::getDWriteFactory()
|
|
{
|
|
static sal::systools::COMReference<IDWriteFactory> pDWriteFactory(
|
|
[]()
|
|
{
|
|
sal::systools::COMReference<IDWriteFactory> pResult;
|
|
HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
|
|
reinterpret_cast<IUnknown**>(&pResult));
|
|
if (FAILED(hr))
|
|
{
|
|
SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
|
|
<< WindowsErrorStringFromHRESULT(hr));
|
|
abort();
|
|
}
|
|
return pResult;
|
|
}());
|
|
return pDWriteFactory.get();
|
|
}
|
|
|
|
// static
|
|
IDWriteGdiInterop* WinSalGraphics::getDWriteGdiInterop()
|
|
{
|
|
static sal::systools::COMReference<IDWriteGdiInterop> pDWriteGdiInterop(
|
|
[]()
|
|
{
|
|
sal::systools::COMReference<IDWriteGdiInterop> pResult;
|
|
HRESULT hr = getDWriteFactory()->GetGdiInterop(&pResult);
|
|
if (FAILED(hr))
|
|
{
|
|
SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr, 16) << ": "
|
|
<< WindowsErrorStringFromHRESULT(hr));
|
|
abort();
|
|
}
|
|
return pResult;
|
|
}());
|
|
return pDWriteGdiInterop.get();
|
|
}
|
|
|
|
sal_uInt16 WinSalGraphics::GetBitCount() const
|
|
{
|
|
return mpImpl->GetBitCount();
|
|
}
|
|
|
|
tools::Long WinSalGraphics::GetGraphicsWidth() const
|
|
{
|
|
return mpImpl->GetGraphicsWidth();
|
|
}
|
|
|
|
void WinSalGraphics::Flush()
|
|
{
|
|
mWinSalGraphicsImplBase->Flush();
|
|
}
|
|
|
|
void WinSalGraphics::ResetClipRegion()
|
|
{
|
|
mpImpl->ResetClipRegion();
|
|
}
|
|
|
|
void WinSalGraphics::setClipRegion( const vcl::Region& i_rClip )
|
|
{
|
|
mpImpl->setClipRegion( i_rClip );
|
|
}
|
|
|
|
void WinSalGraphics::SetLineColor()
|
|
{
|
|
mpImpl->SetLineColor();
|
|
}
|
|
|
|
void WinSalGraphics::SetLineColor( Color nColor )
|
|
{
|
|
mpImpl->SetLineColor( nColor );
|
|
}
|
|
|
|
void WinSalGraphics::SetFillColor()
|
|
{
|
|
mpImpl->SetFillColor();
|
|
}
|
|
|
|
void WinSalGraphics::SetFillColor( Color nColor )
|
|
{
|
|
mpImpl->SetFillColor( nColor );
|
|
}
|
|
|
|
void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly )
|
|
{
|
|
mpImpl->SetXORMode( bSet, bInvertOnly );
|
|
}
|
|
|
|
void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
|
|
{
|
|
mpImpl->SetROPLineColor( nROPColor );
|
|
}
|
|
|
|
void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
|
|
{
|
|
mpImpl->SetROPFillColor( nROPColor );
|
|
}
|
|
|
|
void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY )
|
|
{
|
|
mpImpl->drawPixel( nX, nY );
|
|
}
|
|
|
|
void WinSalGraphics::drawPixel( tools::Long nX, tools::Long nY, Color nColor )
|
|
{
|
|
mpImpl->drawPixel( nX, nY, nColor );
|
|
}
|
|
|
|
void WinSalGraphics::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 )
|
|
{
|
|
mpImpl->drawLine( nX1, nY1, nX2, nY2 );
|
|
}
|
|
|
|
void WinSalGraphics::drawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
|
|
{
|
|
mpImpl->drawRect( nX, nY, nWidth, nHeight );
|
|
}
|
|
|
|
void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry )
|
|
{
|
|
mpImpl->drawPolyLine( nPoints, pPtAry );
|
|
}
|
|
|
|
void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const Point* pPtAry )
|
|
{
|
|
mpImpl->drawPolygon( nPoints, pPtAry );
|
|
}
|
|
|
|
void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
|
|
const Point** pPtAry )
|
|
{
|
|
mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry );
|
|
}
|
|
|
|
bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
|
|
{
|
|
return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry );
|
|
}
|
|
|
|
bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry )
|
|
{
|
|
return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry );
|
|
}
|
|
|
|
bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
|
|
const Point* const* pPtAry, const PolyFlags* const* pFlgAry )
|
|
{
|
|
return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry );
|
|
}
|
|
|
|
bool WinSalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient)
|
|
{
|
|
return mpImpl->drawGradient(rPoly, rGradient);
|
|
}
|
|
|
|
bool WinSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient)
|
|
{
|
|
return mpImpl->implDrawGradient(rPolyPolygon, rGradient);
|
|
}
|
|
|
|
static BYTE* ImplSearchEntry( BYTE* pSource, BYTE const * pDest, sal_uLong nComp, sal_uLong nSize )
|
|
{
|
|
while ( nComp-- >= nSize )
|
|
{
|
|
sal_uLong i;
|
|
for ( i = 0; i < nSize; i++ )
|
|
{
|
|
if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
|
|
break;
|
|
}
|
|
if ( i == nSize )
|
|
return pSource;
|
|
pSource++;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
|
|
{
|
|
bool bRetValue = false;
|
|
BYTE* pDest = ImplSearchEntry( pSource, reinterpret_cast<BYTE const *>("%%BoundingBox:"), nSize, 14 );
|
|
if ( pDest )
|
|
{
|
|
nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
|
|
pDest += 14;
|
|
|
|
int nSizeLeft = nSize - ( pDest - pSource );
|
|
if ( nSizeLeft > 100 )
|
|
nSizeLeft = 100; // only 100 bytes following the bounding box will be checked
|
|
|
|
int i;
|
|
for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
|
|
{
|
|
int nDivision = 1;
|
|
bool bDivision = false;
|
|
bool bNegative = false;
|
|
bool bValid = true;
|
|
|
|
while ( ( --nSizeLeft ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) ) pDest++;
|
|
BYTE nByte = *pDest;
|
|
while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
|
|
{
|
|
switch ( nByte )
|
|
{
|
|
case '.' :
|
|
if ( bDivision )
|
|
bValid = false;
|
|
else
|
|
bDivision = true;
|
|
break;
|
|
case '-' :
|
|
bNegative = true;
|
|
break;
|
|
default :
|
|
if ( ( nByte < '0' ) || ( nByte > '9' ) )
|
|
nSizeLeft = 1; // error parsing the bounding box values
|
|
else if ( bValid )
|
|
{
|
|
if ( bDivision )
|
|
nDivision*=10;
|
|
nNumb[i] *= 10;
|
|
nNumb[i] += nByte - '0';
|
|
}
|
|
break;
|
|
}
|
|
nSizeLeft--;
|
|
nByte = *(++pDest);
|
|
}
|
|
if ( bNegative )
|
|
nNumb[i] = -nNumb[i];
|
|
if ( bDivision && ( nDivision != 1 ) )
|
|
nNumb[i] /= nDivision;
|
|
}
|
|
if ( i == 4 )
|
|
bRetValue = true;
|
|
}
|
|
return bRetValue;
|
|
}
|
|
|
|
#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
|
|
|
|
bool WinSalGraphics::drawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize )
|
|
{
|
|
bool bRetValue = false;
|
|
|
|
if ( mbPrinter )
|
|
{
|
|
int nEscape = POSTSCRIPT_PASSTHROUGH;
|
|
|
|
if ( Escape( getHDC(), QUERYESCSUPPORT, sizeof( int ), reinterpret_cast<LPSTR>(&nEscape), nullptr ) )
|
|
{
|
|
double nBoundingBox[4];
|
|
|
|
if ( ImplGetBoundingBox( nBoundingBox, static_cast<BYTE*>(pPtr), nSize ) )
|
|
{
|
|
OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
|
|
|
|
// reserve place for a sal_uInt16
|
|
aBuf.append( "aa" );
|
|
|
|
// #107797# Write out EPS encapsulation header
|
|
|
|
// directly taken from the PLRM 3.0, p. 726. Note:
|
|
// this will definitely cause problems when
|
|
// recursively creating and embedding PostScript files
|
|
// in OOo, since we use statically-named variables
|
|
// here (namely, b4_Inc_state_salWin, dict_count_salWin and
|
|
// op_count_salWin). Currently, I have no idea on how to
|
|
// work around that, except from scanning and
|
|
// interpreting the EPS for unused identifiers.
|
|
|
|
// append the real text
|
|
aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
|
|
"/dict_count_salWin countdictstack def\n"
|
|
"/op_count_salWin count 1 sub def\n"
|
|
"userdict begin\n"
|
|
"/showpage {} def\n"
|
|
"0 setgray 0 setlinecap\n"
|
|
"1 setlinewidth 0 setlinejoin\n"
|
|
"10 setmiterlimit [] 0 setdash newpath\n"
|
|
"/languagelevel where\n"
|
|
"{\n"
|
|
" pop languagelevel\n"
|
|
" 1 ne\n"
|
|
" {\n"
|
|
" false setstrokeadjust false setoverprint\n"
|
|
" } if\n"
|
|
"} if\n\n" );
|
|
|
|
// #i10737# Apply clipping manually
|
|
|
|
// Windows seems to ignore any clipping at the HDC,
|
|
// when followed by a POSTSCRIPT_PASSTHROUGH
|
|
|
|
// Check whether we've got a clipping, consisting of
|
|
// exactly one rect (other cases should be, but aren't
|
|
// handled currently)
|
|
|
|
// TODO: Handle more than one rectangle here (take
|
|
// care, the buffer can handle only POSTSCRIPT_BUFSIZE
|
|
// characters!)
|
|
if ( mhRegion != nullptr &&
|
|
mpStdClipRgnData != nullptr &&
|
|
mpClipRgnData == mpStdClipRgnData &&
|
|
mpClipRgnData->rdh.nCount == 1 )
|
|
{
|
|
RECT* pRect = &(mpClipRgnData->rdh.rcBound);
|
|
|
|
aBuf.append( "\nnewpath\n"
|
|
+ OString::number(pRect->left) + " " + OString::number(pRect->top)
|
|
+ " moveto\n"
|
|
+ OString::number(pRect->right) + " " + OString::number(pRect->top)
|
|
+ " lineto\n"
|
|
+ OString::number(pRect->right) + " "
|
|
+ OString::number(pRect->bottom) + " lineto\n"
|
|
+ OString::number(pRect->left) + " "
|
|
+ OString::number(pRect->bottom) + " lineto\n"
|
|
"closepath\n"
|
|
"clip\n"
|
|
"newpath\n" );
|
|
}
|
|
|
|
// #107797# Write out buffer
|
|
|
|
*reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
|
|
Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
|
|
|
|
// #107797# Write out EPS transformation code
|
|
|
|
double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
|
|
double dM22 = nHeight / (nBoundingBox[1] - nBoundingBox[3] );
|
|
// reserve a sal_uInt16 again
|
|
aBuf.setLength( 2 );
|
|
aBuf.append( "\n\n[" + OString::number(dM11) + " 0 0 " + OString::number(dM22) + " "
|
|
+ OString::number(nX - ( dM11 * nBoundingBox[0] )) + " "
|
|
+ OString::number(nY - ( dM22 * nBoundingBox[3] )) + "] concat\n"
|
|
"%%BeginDocument:\n" );
|
|
*reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
|
|
Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
|
|
|
|
// #107797# Write out actual EPS content
|
|
|
|
sal_uLong nToDo = nSize;
|
|
sal_uLong nDoNow;
|
|
while ( nToDo )
|
|
{
|
|
nDoNow = nToDo;
|
|
if ( nToDo > POSTSCRIPT_BUFSIZE - 2 )
|
|
nDoNow = POSTSCRIPT_BUFSIZE - 2;
|
|
// the following is based on the string buffer allocation
|
|
// of size POSTSCRIPT_BUFSIZE at construction time of aBuf
|
|
*reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>(nDoNow);
|
|
memcpy( const_cast<char *>(aBuf.getStr() + 2), static_cast<BYTE*>(pPtr) + nSize - nToDo, nDoNow );
|
|
sal_uLong nResult = Escape ( getHDC(), nEscape, nDoNow + 2, aBuf.getStr(), nullptr );
|
|
if (!nResult )
|
|
break;
|
|
nToDo -= nResult;
|
|
}
|
|
|
|
// #107797# Write out EPS encapsulation footer
|
|
|
|
// reserve a sal_uInt16 again
|
|
aBuf.setLength( 2 );
|
|
aBuf.append( "%%EndDocument\n"
|
|
"count op_count_salWin sub {pop} repeat\n"
|
|
"countdictstack dict_count_salWin sub {end} repeat\n"
|
|
"b4_Inc_state_salWin restore\n\n" );
|
|
*reinterpret_cast<sal_uInt16*>(const_cast<char *>(aBuf.getStr())) = static_cast<sal_uInt16>( aBuf.getLength() - 2 );
|
|
Escape ( getHDC(), nEscape, aBuf.getLength(), aBuf.getStr(), nullptr );
|
|
bRetValue = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRetValue;
|
|
}
|
|
|
|
SystemGraphicsData WinSalGraphics::GetGraphicsData() const
|
|
{
|
|
SystemGraphicsData aRes;
|
|
aRes.nSize = sizeof(aRes);
|
|
aRes.hDC = getHDC();
|
|
return aRes;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|