summaryrefslogtreecommitdiff
path: root/vcl/win
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/win')
-rwxr-xr-xvcl/win/source/app/saldata.cxx168
-rwxr-xr-xvcl/win/source/app/salinfo.cxx293
-rwxr-xr-xvcl/win/source/app/salinst.cxx1140
-rwxr-xr-xvcl/win/source/app/salshl.cxx165
-rwxr-xr-xvcl/win/source/app/saltimer.cxx154
-rwxr-xr-xvcl/win/source/gdi/salbmp.cxx636
-rw-r--r--vcl/win/source/gdi/salgdi.cxx1826
-rw-r--r--vcl/win/source/gdi/salgdi2.cxx824
-rwxr-xr-xvcl/win/source/gdi/salgdi3.cxx3079
-rw-r--r--vcl/win/source/gdi/salgdi_gdiplus.cxx267
-rwxr-xr-xvcl/win/source/gdi/salnativewidgets-luna.cxx1419
-rw-r--r--vcl/win/source/gdi/salprn.cxx2372
-rwxr-xr-xvcl/win/source/gdi/salvd.cxx259
-rwxr-xr-xvcl/win/source/gdi/winlayout.cxx3186
-rwxr-xr-xvcl/win/source/gdi/wntgdi.cxx67
-rw-r--r--vcl/win/source/src/50.bmpbin0 -> 94 bytes
-rw-r--r--vcl/win/source/src/50.pngbin0 -> 125 bytes
-rw-r--r--vcl/win/source/src/airbrush.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/ase.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asn.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asne.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asns.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asnswe.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asnw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/ass.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asse.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/assw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/asw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/aswe.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/chain.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/chainnot.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/chart.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copydata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copydlnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyf.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyf2.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/copyflnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/crook.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/crop.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/cross.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/darc.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dbezier.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dcapt.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dcirccut.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dconnect.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dellipse.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/detectiv.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dfree.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dline.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dpie.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dpolygon.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/drect.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/dtext.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/fill.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hand.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/help.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hshear.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsizebar.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/hsplit.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/linkdata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/linkf.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/magnify.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/mirror.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/move.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movebw.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movedata.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movedlnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movef.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movef2.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/moveflnk.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/movept.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/neswsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/notallow.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/nullptr.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/nwsesize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pen.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotcol.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotdel.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotfld.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pivotrow.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/pntbrsh.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/refhand.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/rotate.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/salsrc.rc121
-rw-r--r--vcl/win/source/src/sd.icobin0 -> 3310 bytes
-rw-r--r--vcl/win/source/src/tblsele.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblsels.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselse.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselsw.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/tblselw.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/timemove.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/src/timesize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vshear.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsize.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsizebar.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vsplit.curbin0 -> 326 bytes
-rw-r--r--vcl/win/source/src/vtext.curbin0 -> 326 bytes
-rwxr-xr-xvcl/win/source/window/salframe.cxx6388
-rwxr-xr-xvcl/win/source/window/salmenu.cxx414
-rwxr-xr-xvcl/win/source/window/salobj.cxx878
101 files changed, 23656 insertions, 0 deletions
diff --git a/vcl/win/source/app/saldata.cxx b/vcl/win/source/app/saldata.cxx
new file mode 100755
index 000000000000..4faaf7bd4def
--- /dev/null
+++ b/vcl/win/source/app/saldata.cxx
@@ -0,0 +1,168 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "tools/svwin.h"
+#include "rtl/tencinfo.h"
+#include "vcl/svapp.hxx"
+
+#include "win/saldata.hxx"
+
+// =======================================================================
+
+rtl_TextEncoding ImplSalGetSystemEncoding()
+{
+ static UINT nOldAnsiCodePage = 0;
+ static rtl_TextEncoding eEncoding = RTL_TEXTENCODING_MS_1252;
+
+ UINT nAnsiCodePage = GetACP();
+ if ( nAnsiCodePage != nOldAnsiCodePage )
+ {
+ rtl_TextEncoding nEnc
+ = rtl_getTextEncodingFromWindowsCodePage(nAnsiCodePage);
+ if (nEnc != RTL_TEXTENCODING_DONTKNOW)
+ eEncoding = nEnc;
+ }
+
+ return eEncoding;
+}
+
+// -----------------------------------------------------------------------
+
+ByteString ImplSalGetWinAnsiString( const UniString& rStr, sal_Bool bFileName )
+{
+ rtl_TextEncoding eEncoding = ImplSalGetSystemEncoding();
+ if ( bFileName )
+ {
+ return ByteString( rStr, eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_UNDERLINE |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_UNDERLINE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 );
+ }
+ else
+ {
+ return ByteString( rStr, eEncoding,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE |
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACESTR |
+ RTL_UNICODETOTEXT_FLAGS_PRIVATE_MAPTO0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen )
+{
+ return UniString( pStr, nLen, ImplSalGetSystemEncoding(),
+ RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
+}
+
+// =======================================================================
+
+int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 )
+{
+ int nRet;
+ wchar_t c1;
+ char c2;
+ do
+ {
+ // Ist das Zeichen zwischen 'A' und 'Z' dann umwandeln
+ c1 = *pStr1;
+ c2 = *pStr2;
+ if ( (c1 >= 65) && (c1 <= 90) )
+ c1 += 32;
+ if ( (c2 >= 65) && (c2 <= 90) )
+ c2 += 32;
+ nRet = ((sal_Int32)c1)-((sal_Int32)((unsigned char)c2));
+ if ( nRet != 0 )
+ break;
+
+ pStr1++;
+ pStr2++;
+ }
+ while ( c2 );
+
+ return nRet;
+}
+
+// =======================================================================
+
+LONG ImplSetWindowLong( HWND hWnd, int nIndex, DWORD dwNewLong )
+{
+ return SetWindowLongW( hWnd, nIndex, dwNewLong );
+}
+
+// -----------------------------------------------------------------------
+
+LONG ImplGetWindowLong( HWND hWnd, int nIndex )
+{
+ return GetWindowLongW( hWnd, nIndex );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplPostMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ return PostMessageW( hWnd, nMsg, wParam, lParam );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplSendMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ BOOL bRet = SendMessageW( hWnd, nMsg, wParam, lParam );
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplGetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax )
+{
+ return GetMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax );
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplPeekMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg )
+{
+ return PeekMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg );
+}
+
+// -----------------------------------------------------------------------
+
+LONG ImplDispatchMessage( CONST MSG *lpMsg )
+{
+ return DispatchMessageW( lpMsg );
+}
+
diff --git a/vcl/win/source/app/salinfo.cxx b/vcl/win/source/app/salinfo.cxx
new file mode 100755
index 000000000000..431e9ca9c15f
--- /dev/null
+++ b/vcl/win/source/app/salinfo.cxx
@@ -0,0 +1,293 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// rely on unicows on for multimon functions for older versions
+#if WINVER < 0x0500
+#undef WINVER
+#define WINVER 0x0500
+#endif
+
+#include "svsys.h"
+#include "rtl/ustrbuf.hxx"
+
+#include "tools/debug.hxx"
+#include "tools/string.hxx"
+
+#include "vcl/window.hxx"
+
+#include "win/salsys.h"
+#include "win/salframe.h"
+#include "win/salinst.h"
+#include "win/saldata.hxx"
+
+#include "svdata.hxx"
+
+#include <hash_map>
+
+SalSystem* WinSalInstance::CreateSalSystem()
+{
+ return new WinSalSystem();
+}
+
+WinSalSystem::~WinSalSystem()
+{
+}
+
+// -----------------------------------------------------------------------
+
+static BOOL CALLBACK ImplEnumMonitorProc( HMONITOR hMonitor,
+ HDC hDC,
+ LPRECT lpRect,
+ LPARAM dwData )
+{
+ WinSalSystem* pSys = reinterpret_cast<WinSalSystem*>(dwData);
+ return pSys->handleMonitorCallback( reinterpret_cast<sal_IntPtr>(hMonitor),
+ reinterpret_cast<sal_IntPtr>(hDC),
+ reinterpret_cast<sal_IntPtr>(lpRect) );
+}
+
+sal_Bool WinSalSystem::handleMonitorCallback( sal_IntPtr hMonitor, sal_IntPtr, sal_IntPtr )
+{
+ MONITORINFOEXW aInfo;
+ aInfo.cbSize = sizeof( aInfo );
+ if( GetMonitorInfoW( reinterpret_cast<HMONITOR>(hMonitor), &aInfo ) )
+ {
+ aInfo.szDevice[CCHDEVICENAME-1] = 0;
+ rtl::OUString aDeviceName( reinterpret_cast<const sal_Unicode *>(aInfo.szDevice) );
+ std::map< rtl::OUString, unsigned int >::const_iterator it =
+ m_aDeviceNameToMonitor.find( aDeviceName );
+ if( it != m_aDeviceNameToMonitor.end() )
+ {
+ DisplayMonitor& rMon( m_aMonitors[ it->second ] );
+ rMon.m_aArea = Rectangle( Point( aInfo.rcMonitor.left,
+ aInfo.rcMonitor.top ),
+ Size( aInfo.rcMonitor.right - aInfo.rcMonitor.left,
+ aInfo.rcMonitor.bottom - aInfo.rcMonitor.top ) );
+ rMon.m_aWorkArea = Rectangle( Point( aInfo.rcWork.left,
+ aInfo.rcWork.top ),
+ Size( aInfo.rcWork.right - aInfo.rcWork.left,
+ aInfo.rcWork.bottom - aInfo.rcWork.top ) );
+ if( (aInfo.dwFlags & MONITORINFOF_PRIMARY) != 0 )
+ m_nPrimary = it->second;
+ }
+ }
+ return sal_True;
+}
+
+void WinSalSystem::clearMonitors()
+{
+ m_aMonitors.clear();
+ m_nPrimary = 0;
+}
+
+bool WinSalSystem::initMonitors()
+{
+ if( m_aMonitors.size() > 0 )
+ return true;
+
+ bool winVerOk = true;
+
+ // multi monitor calls not available on Win95/NT
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion <= 4 )
+ winVerOk = false; // NT
+ }
+ else if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion == 4 && aSalShlData.maVersionInfo.dwMinorVersion == 0 )
+ winVerOk = false; // Win95
+ }
+ if( winVerOk )
+ {
+ int nMonitors = GetSystemMetrics( SM_CMONITORS );
+ if( nMonitors == 1 )
+ {
+ int w = GetSystemMetrics( SM_CXSCREEN );
+ int h = GetSystemMetrics( SM_CYSCREEN );
+ m_aMonitors.push_back( DisplayMonitor( rtl::OUString(),
+ rtl::OUString(),
+ Rectangle( Point(), Size( w, h ) ),
+ Rectangle( Point(), Size( w, h ) ),
+ 0 ) );
+ m_aDeviceNameToMonitor[ rtl::OUString() ] = 0;
+ m_nPrimary = 0;
+ RECT aWorkRect;
+ if( SystemParametersInfo( SPI_GETWORKAREA, 0, &aWorkRect, 0 ) )
+ m_aMonitors.back().m_aWorkArea = Rectangle( aWorkRect.left, aWorkRect.top,
+ aWorkRect.right, aWorkRect.bottom );
+ }
+ else
+ {
+ DISPLAY_DEVICEW aDev;
+ aDev.cb = sizeof( aDev );
+ DWORD nDevice = 0;
+ std::hash_map< rtl::OUString, int, rtl::OUStringHash > aDeviceStringCount;
+ while( EnumDisplayDevicesW( NULL, nDevice++, &aDev, 0 ) )
+ {
+ if( (aDev.StateFlags & DISPLAY_DEVICE_ACTIVE)
+ && !(aDev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ) // sort out non/disabled monitors
+ {
+ aDev.DeviceName[31] = 0;
+ aDev.DeviceString[127] = 0;
+ rtl::OUString aDeviceName( reinterpret_cast<const sal_Unicode *>(aDev.DeviceName) );
+ rtl::OUString aDeviceString( reinterpret_cast<const sal_Unicode *>(aDev.DeviceString) );
+ if( aDeviceStringCount.find( aDeviceString ) == aDeviceStringCount.end() )
+ aDeviceStringCount[ aDeviceString ] = 1;
+ else
+ aDeviceStringCount[ aDeviceString ]++;
+ m_aDeviceNameToMonitor[ aDeviceName ] = m_aMonitors.size();
+ m_aMonitors.push_back( DisplayMonitor( aDeviceString,
+ aDeviceName,
+ Rectangle(),
+ Rectangle(),
+ aDev.StateFlags ) );
+ }
+ }
+ HDC aDesktopRC = GetDC( NULL );
+ EnumDisplayMonitors( aDesktopRC, NULL, ImplEnumMonitorProc, reinterpret_cast<LPARAM>(this) );
+
+ // append monitor numbers to name strings
+ std::hash_map< rtl::OUString, int, rtl::OUStringHash > aDevCount( aDeviceStringCount );
+ unsigned int nMonitors = m_aMonitors.size();
+ for( unsigned int i = 0; i < nMonitors; i++ )
+ {
+ const rtl::OUString& rDev( m_aMonitors[i].m_aName );
+ if( aDeviceStringCount[ rDev ] > 1 )
+ {
+ int nInstance = aDeviceStringCount[ rDev ] - (-- aDevCount[ rDev ] );
+ rtl::OUStringBuffer aBuf( rDev.getLength() + 8 );
+ aBuf.append( rDev );
+ aBuf.appendAscii( " (" );
+ aBuf.append( sal_Int32( nInstance ) );
+ aBuf.append( sal_Unicode(')') );
+ m_aMonitors[ i ].m_aName = aBuf.makeStringAndClear();
+ }
+ }
+ }
+ }
+ else
+ {
+ int w = GetSystemMetrics( SM_CXSCREEN );
+ int h = GetSystemMetrics( SM_CYSCREEN );
+ m_aMonitors.push_back( DisplayMonitor( rtl::OUString(),
+ rtl::OUString(),
+ Rectangle( Point(), Size( w, h ) ),
+ Rectangle( Point(), Size( w, h ) ),
+ 0 ) );
+ m_aDeviceNameToMonitor[ rtl::OUString() ] = 0;
+ m_nPrimary = 0;
+ RECT aWorkRect;
+ if( SystemParametersInfo( SPI_GETWORKAREA, 0, &aWorkRect, 0 ) )
+ m_aMonitors.back().m_aWorkArea = Rectangle( aWorkRect.left, aWorkRect.top,
+ aWorkRect.right, aWorkRect.bottom );
+ }
+
+ return m_aMonitors.size() > 0;
+}
+
+unsigned int WinSalSystem::GetDisplayScreenCount()
+{
+ initMonitors();
+ return m_aMonitors.size();
+}
+
+bool WinSalSystem::IsMultiDisplay()
+{
+ return false;
+}
+
+unsigned int WinSalSystem::GetDefaultDisplayNumber()
+{
+ initMonitors();
+ return m_nPrimary;
+}
+
+Rectangle WinSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aArea : Rectangle();
+}
+
+Rectangle WinSalSystem::GetDisplayWorkAreaPosSizePixel( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aWorkArea : Rectangle();
+}
+
+rtl::OUString WinSalSystem::GetScreenName( unsigned int nScreen )
+{
+ initMonitors();
+ return (nScreen < m_aMonitors.size()) ? m_aMonitors[nScreen].m_aName : rtl::OUString();
+}
+
+// -----------------------------------------------------------------------
+/* We have to map the button identifier to the identifier used by the Win32
+ Platform SDK to specify the default button for the MessageBox API.
+ The first dimension is the button combination, the second dimension
+ is the button identifier.
+*/
+static int DEFAULT_BTN_MAPPING_TABLE[][8] =
+{
+ // Undefined OK CANCEL ABORT RETRY IGNORE YES NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //OK_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1 }, //ABORT_RETRY_IGNO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON3, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO_CANCEL
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2 }, //YES_NO
+ { MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1, MB_DEFBUTTON1 } //RETRY_CANCEL
+};
+
+int WinSalSystem::ShowNativeMessageBox(const String& rTitle, const String& rMessage, int nButtonCombination, int nDefaultButton)
+{
+ DBG_ASSERT( nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO, "Invalid arguments!" );
+
+ int nFlags = MB_TASKMODAL | MB_SETFOREGROUND | MB_ICONWARNING | nButtonCombination;
+
+ if (nButtonCombination >= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_OK &&
+ nButtonCombination <= SALSYSTEM_SHOWNATIVEMSGBOX_BTNCOMBI_RETRY_CANCEL &&
+ nDefaultButton >= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK &&
+ nDefaultButton <= SALSYSTEM_SHOWNATIVEMSGBOX_BTN_NO)
+ nFlags |= DEFAULT_BTN_MAPPING_TABLE[nButtonCombination][nDefaultButton];
+
+ //#107209 hide the splash screen if active
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->mpIntroWindow)
+ pSVData->mpIntroWindow->Hide();
+
+ return MessageBoxW(
+ 0,
+ reinterpret_cast<LPCWSTR>(rMessage.GetBuffer()),
+ reinterpret_cast<LPCWSTR>(rTitle.GetBuffer()),
+ nFlags);
+}
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx
new file mode 100755
index 000000000000..1e5a306d852d
--- /dev/null
+++ b/vcl/win/source/app/salinst.cxx
@@ -0,0 +1,1140 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <tools/svwin.h>
+#ifdef WNT
+#include <process.h>
+#endif
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+
+#include <osl/file.hxx>
+
+#include <vos/mutex.hxx>
+
+#include <tools/solarmutex.hxx>
+#include <tools/debug.hxx>
+
+#include <vcl/timer.hxx>
+#include <vcl/apptypes.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/salids.hrc>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salframe.h>
+#include <win/salobj.h>
+#include <win/saltimer.h>
+#include <win/salbmp.h>
+
+#include <salimestatus.hxx>
+#include <salsys.hxx>
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#pragma warning( disable: 4917 )
+#endif
+
+#include <GdiPlus.h>
+#include <GdiPlusEnums.h>
+#include <GdiPlusColor.h>
+#include <Shlobj.h>
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+// =======================================================================
+
+void SalAbort( const XubString& rErrorText )
+{
+ ImplFreeSalGDI();
+
+ if ( !rErrorText.Len() )
+ {
+ // #112255# make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
+ FatalAppExit( 0, "Application Error" );
+ }
+ else
+ {
+ // #112255# make sure crash reporter is triggered
+ RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
+ ByteString aErrorText( ImplSalGetWinAnsiString( rErrorText ) );
+ FatalAppExit( 0, aErrorText.GetBuffer() );
+ }
+}
+
+// =======================================================================
+
+LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
+
+// =======================================================================
+
+class SalYieldMutex : public vos::OMutex
+{
+public: // for ImplSalYield()
+ WinSalInstance* mpInstData;
+ sal_uLong mnCount;
+ DWORD mnThreadId;
+
+public:
+ SalYieldMutex( WinSalInstance* pInstData );
+
+ virtual void SAL_CALL acquire();
+ virtual void SAL_CALL release();
+ virtual sal_Bool SAL_CALL tryToAcquire();
+
+ sal_uLong GetAcquireCount( sal_uLong nThreadId );
+};
+
+// -----------------------------------------------------------------------
+
+SalYieldMutex::SalYieldMutex( WinSalInstance* pInstData )
+{
+ mpInstData = pInstData;
+ mnCount = 0;
+ mnThreadId = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL SalYieldMutex::acquire()
+{
+ OMutex::acquire();
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+}
+
+// -----------------------------------------------------------------------
+
+void SAL_CALL SalYieldMutex::release()
+{
+ DWORD nThreadId = GetCurrentThreadId();
+ if ( mnThreadId != nThreadId )
+ OMutex::release();
+ else
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId != nThreadId )
+ {
+ if ( mnCount == 1 )
+ {
+ // If we don't call these message, the Output from the
+ // Java clients doesn't come in the right order
+ GdiFlush();
+
+ mpInstData->mpSalWaitMutex->acquire();
+ if ( mpInstData->mnYieldWaitCount )
+ ImplPostMessage( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ mpInstData->mpSalWaitMutex->release();
+ }
+ else
+ {
+ mnCount--;
+ OMutex::release();
+ }
+ }
+ else
+ {
+ if ( mnCount == 1 )
+ mnThreadId = 0;
+ mnCount--;
+ OMutex::release();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool SAL_CALL SalYieldMutex::tryToAcquire()
+{
+ if( OMutex::tryToAcquire() )
+ {
+ mnCount++;
+ mnThreadId = GetCurrentThreadId();
+ return sal_True;
+ }
+ else
+ return sal_False;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId )
+{
+ if ( nThreadId == mnThreadId )
+ return mnCount;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquireWithWait()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ // If we are the main thread, then we must wait with wait, because
+ // in if we don't reschedule, then we create deadlocks if a Windows
+ // Function is called from another thread. If we arn't the main thread,
+ // than we call qcquire directly.
+ DWORD nThreadId = GetCurrentThreadId();
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId == nThreadId )
+ {
+ // Wenn wir den Mutex nicht bekommen, muessen wir solange
+ // warten, bis wir Ihn bekommen
+ sal_Bool bAcquire = FALSE;
+ do
+ {
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ bAcquire = TRUE;
+ else
+ {
+ pInst->mpSalWaitMutex->acquire();
+ if ( pInst->mpSalYieldMutex->tryToAcquire() )
+ {
+ bAcquire = TRUE;
+ pInst->mpSalWaitMutex->release();
+ }
+ else
+ {
+ pInst->mnYieldWaitCount++;
+ pInst->mpSalWaitMutex->release();
+ MSG aTmpMsg;
+ ImplGetMessage( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
+ pInst->mnYieldWaitCount--;
+ if ( pInst->mnYieldWaitCount )
+ ImplPostMessage( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
+ }
+ }
+ }
+ while ( !bAcquire );
+ }
+ else
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplSalYieldMutexTryToAcquire()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ return pInst->mpSalYieldMutex->tryToAcquire();
+ else
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexAcquire()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ pInst->mpSalYieldMutex->acquire();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYieldMutexRelease()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst )
+ {
+ GdiFlush();
+ pInst->mpSalYieldMutex->release();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong ImplSalReleaseYieldMutex()
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return 0;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ sal_uLong nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
+ sal_uLong n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalAcquireYieldMutex( sal_uLong nCount )
+{
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( !pInst )
+ return;
+
+ SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
+ while ( nCount )
+ {
+ pYieldMutex->acquire();
+ nCount--;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalInstance::CheckYieldMutex()
+{
+ bool bRet = true;
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ bRet = false;
+ }
+ }
+ }
+ else
+ {
+ if ( pSalData->mpFirstInstance )
+ {
+ SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
+ if ( pYieldMutex->mnThreadId != nCurThreadId )
+ {
+ bRet = false;
+ }
+ }
+ }
+ return bRet;
+}
+
+// =======================================================================
+
+void SalData::initKeyCodeMap()
+{
+ UINT nKey = 0xffffffff;
+ #define initKey( a, b )\
+ nKey = LOWORD( VkKeyScan( a ) );\
+ if( nKey < 0xffff )\
+ maVKMap[ nKey ] = b;
+
+ initKey( '+', KEY_ADD );
+ initKey( '-', KEY_SUBTRACT );
+ initKey( '*', KEY_MULTIPLY );
+ initKey( '/', KEY_DIVIDE );
+ initKey( '.', KEY_POINT );
+ initKey( ',', KEY_COMMA );
+ initKey( '<', KEY_LESS );
+ initKey( '>', KEY_GREATER );
+ initKey( '=', KEY_EQUAL );
+ initKey( '~', KEY_TILDE );
+ initKey( '`', KEY_QUOTELEFT );
+}
+
+// =======================================================================
+// -------
+// SalData
+// -------
+
+SalData::SalData()
+{
+ mhInst = 0; // default instance handle
+ mhPrevInst = 0; // previous instance handle
+ mnCmdShow = 0; // default frame show style
+ mhDitherPal = 0; // dither palette
+ mhDitherDIB = 0; // dither memory handle
+ mpDitherDIB = 0; // dither memory
+ mpDitherDIBData = 0; // beginning of DIB data
+ mpDitherDiff = 0; // Dither mapping table
+ mpDitherLow = 0; // Dither mapping table
+ mpDitherHigh = 0; // Dither mapping table
+ mnTimerMS = 0; // Current Time (in MS) of the Timer
+ mnTimerOrgMS = 0; // Current Original Time (in MS)
+ mnNextTimerTime = 0;
+ mnLastEventTime = 0;
+ mnTimerId = 0; // windows timer id
+ mbInTimerProc = FALSE; // timer event is currently being dispatched
+ mhSalObjMsgHook = 0; // hook to get interesting msg for SalObject
+ mhWantLeaveMsg = 0; // window handle, that want a MOUSELEAVE message
+ mpMouseLeaveTimer = 0; // Timer for MouseLeave Test
+ mpFirstInstance = 0; // pointer of first instance
+ mpFirstFrame = 0; // pointer of first frame
+ mpFirstObject = 0; // pointer of first object window
+ mpFirstVD = 0; // first VirDev
+ mpFirstPrinter = 0; // first printing printer
+ mpHDCCache = 0; // Cache for three DC's
+ mh50Bmp = 0; // 50% Bitmap
+ mh50Brush = 0; // 50% Brush
+ int i;
+ for(i=0; i<MAX_STOCKPEN; i++)
+ {
+ maStockPenColorAry[i] = 0;
+ mhStockPenAry[i] = 0;
+ }
+ for(i=0; i<MAX_STOCKBRUSH; i++)
+ {
+ maStockBrushColorAry[i] = 0;
+ mhStockBrushAry[i] = 0;
+ }
+ mnStockPenCount = 0; // count of static pens
+ mnStockBrushCount = 0; // count of static brushes
+ mnSalObjWantKeyEvt = 0; // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll
+ mnCacheDCInUse = 0; // count of CacheDC in use
+ mbObjClassInit = FALSE; // is SALOBJECTCLASS initialised
+ mbInPalChange = FALSE; // is in WM_QUERYNEWPALETTE
+ mnAppThreadId = 0; // Id from Applikation-Thread
+ mbScrSvrEnabled = FALSE; // ScreenSaver enabled
+ mnSageStatus = 0; // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden)
+ mpSageEnableProc = 0; // funktion to deactivate the system agent
+ mpFirstIcon = 0; // icon cache, points to first icon, NULL if none
+ mpTempFontItem = 0;
+ mbThemeChanged = FALSE; // true if visual theme was changed: throw away theme handles
+ mbThemeMenuSupport = FALSE;
+
+ // init with NULL
+ gdiplusToken = 0;
+ maDwmLib = 0;
+ mpDwmIsCompositionEnabled = 0;
+
+ initKeyCodeMap();
+
+ SetSalData( this );
+ initNWF();
+}
+
+SalData::~SalData()
+{
+ deInitNWF();
+ SetSalData( NULL );
+}
+
+void InitSalData()
+{
+ SalData* pSalData = new SalData;
+ CoInitialize(0);
+
+ // init GDIPlus
+ static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
+ Gdiplus::GdiplusStartup(&pSalData->gdiplusToken, &gdiplusStartupInput, NULL);
+}
+
+
+void DeInitSalData()
+{
+ CoUninitialize();
+ SalData* pSalData = GetSalData();
+
+ // deinit GDIPlus
+ if(pSalData)
+ {
+ Gdiplus::GdiplusShutdown(pSalData->gdiplusToken);
+ }
+
+ delete pSalData;
+}
+
+// -----------------------------------------------------------------------
+
+void InitSalMain()
+{
+ // remember data, copied from WinMain
+ SalData* pData = GetAppSalData();
+ if ( pData ) // Im AppServer NULL
+ {
+ STARTUPINFO aSI;
+ aSI.cb = sizeof( aSI );
+ GetStartupInfo( &aSI );
+ pData->mhInst = GetModuleHandle( NULL );
+ pData->mhPrevInst = NULL;
+ pData->mnCmdShow = aSI.wShowWindow;
+ }
+}
+
+void DeInitSalMain()
+{
+}
+
+// -----------------------------------------------------------------------
+
+SalInstance* CreateSalInstance()
+{
+ SalData* pSalData = GetSalData();
+
+ // determine the windows version
+ aSalShlData.mbWXP = 0;
+ aSalShlData.mbWPrinter = 0;
+ WORD nVer = (WORD)GetVersion();
+ aSalShlData.mnVersion = (((WORD)LOBYTE(nVer)) * 100) + HIBYTE(nVer);
+ if ( aSalShlData.mnVersion >= 400 )
+ aSalShlData.mbW40 = 1;
+ rtl_zeroMemory( &aSalShlData.maVersionInfo, sizeof(aSalShlData.maVersionInfo) );
+ aSalShlData.maVersionInfo.dwOSVersionInfoSize = sizeof( aSalShlData.maVersionInfo );
+ if ( GetVersionEx( &aSalShlData.maVersionInfo ) )
+ {
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ // Windows XP ?
+ if ( aSalShlData.maVersionInfo.dwMajorVersion > 5 ||
+ ( aSalShlData.maVersionInfo.dwMajorVersion == 5 && aSalShlData.maVersionInfo.dwMinorVersion >= 1 ) )
+ aSalShlData.mbWXP = 1;
+ if( aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ aSalShlData.mbWPrinter = 1;
+ }
+ }
+
+ pSalData->mnAppThreadId = GetCurrentThreadId();
+
+ // register frame class
+ if ( !pSalData->mhPrevInst )
+ {
+ WNDCLASSEXW aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = CS_OWNDC;
+ aWndClassEx.lpfnWndProc = SalFrameWndProcW;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_FRAME_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hCursor = 0;
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_FRAME_CLASSNAMEW;
+ ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.style |= CS_SAVEBITS;
+ aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ // shadow effect for popups on XP
+ if( aSalShlData.mbWXP )
+ aWndClassEx.style |= CS_DROPSHADOW;
+ aWndClassEx.lpszClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalComWndProcW;
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEW;
+ if ( !RegisterClassExW( &aWndClassEx ) )
+ return NULL;
+ }
+
+ HWND hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW,
+ L"", WS_POPUP, 0, 0, 0, 0, 0, 0,
+ pSalData->mhInst, NULL );
+ if ( !hComWnd )
+ return NULL;
+
+ WinSalInstance* pInst = new WinSalInstance;
+
+ // init instance (only one instance in this version !!!)
+ pSalData->mpFirstInstance = pInst;
+ pInst->mhInst = pSalData->mhInst;
+ pInst->mhComWnd = hComWnd;
+
+ // init static GDI Data
+ ImplInitSalGDI();
+
+ return pInst;
+}
+
+// -----------------------------------------------------------------------
+
+void DestroySalInstance( SalInstance* pInst )
+{
+ SalData* pSalData = GetSalData();
+
+ // (only one instance in this version !!!)
+
+ ImplFreeSalGDI();
+
+ // reset instance
+ if ( pSalData->mpFirstInstance == pInst )
+ pSalData->mpFirstInstance = NULL;
+
+ delete pInst;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInstance::WinSalInstance()
+{
+ mhComWnd = 0;
+ mpSalYieldMutex = new SalYieldMutex( this );
+ mpSalWaitMutex = new vos::OMutex;
+ mnYieldWaitCount = 0;
+ mpSalYieldMutex->acquire();
+ ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInstance::~WinSalInstance()
+{
+ ::tools::SolarMutex::SetSolarMutex( 0 );
+ mpSalYieldMutex->release();
+ delete mpSalYieldMutex;
+ delete mpSalWaitMutex;
+ DestroyWindow( mhComWnd );
+}
+
+// -----------------------------------------------------------------------
+
+vos::IMutex* WinSalInstance::GetYieldMutex()
+{
+ return mpSalYieldMutex;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong WinSalInstance::ReleaseYieldMutex()
+{
+ return ImplSalReleaseYieldMutex();
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::AcquireYieldMutex( sal_uLong nCount )
+{
+ ImplSalAcquireYieldMutex( nCount );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalDispatchMessage( MSG* pMsg )
+{
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstObject )
+ {
+ if ( ImplSalPreDispatchMsg( pMsg ) )
+ return;
+ }
+ LRESULT lResult = ImplDispatchMessage( pMsg );
+ if ( pSalData->mpFirstObject )
+ ImplSalPostDispatchMsg( pMsg, lResult );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalYield( sal_Bool bWait, sal_Bool bHandleAllCurrentEvents )
+{
+ MSG aMsg;
+ bool bWasMsg = false, bOneEvent = false;
+
+ int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
+ do
+ {
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplSalDispatchMessage( &aMsg );
+ }
+
+ bOneEvent = bWasMsg = true;
+ }
+ else
+ bOneEvent = false;
+ } while( --nMaxEvents && bOneEvent );
+
+ if ( bWait && ! bWasMsg )
+ {
+ if ( ImplGetMessage( &aMsg, 0, 0, 0 ) )
+ {
+ if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplSalDispatchMessage( &aMsg );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
+{
+ SalYieldMutex* pYieldMutex = mpSalYieldMutex;
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ sal_uLong nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
+ sal_uLong n = nCount;
+ while ( n )
+ {
+ pYieldMutex->release();
+ n--;
+ }
+ if ( pSalData->mnAppThreadId != nCurThreadId )
+ {
+ // #97739# A SendMessage call blocks until the called thread (here: the main thread)
+ // returns. During a yield however, messages are processed in the main thread that might
+ // result in a new message loop due to opening a dialog. Thus, SendMessage would not
+ // return which will block this thread!
+ // Solution: just give up the time slice and hope that messages are processed
+ // by the main thread anyway (where all windows are created)
+ // If the mainthread is not currently handling messages, then our SendMessage would
+ // also do nothing, so this seems to be reasonable.
+
+ // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
+ if( ImplGetSVData()->maAppData.mnModalMode )
+ Sleep(1);
+ else
+ ImplSendMessage( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ pYieldMutex->acquire();
+ n--;
+ }
+ }
+ else
+ {
+ ImplSalYield( bWait, bHandleAllCurrentEvents );
+
+ n = nCount;
+ while ( n )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ n--;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+
+
+ switch ( nMsg )
+ {
+ case SAL_MSG_PRINTABORTJOB:
+ ImplSalPrinterAbortJobAsync( (HDC)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_THREADYIELD:
+ ImplSalYield( (sal_Bool)wParam, (sal_Bool)lParam );
+ rDef = FALSE;
+ break;
+ // If we get this message, because another GetMessage() call
+ // has recieved this message, we must post this message to
+ // us again, because in the other case we wait forever.
+ case SAL_MSG_RELEASEWAITYIELD:
+ {
+ WinSalInstance* pInst = GetSalData()->mpFirstInstance;
+ if ( pInst && pInst->mnYieldWaitCount )
+ ImplPostMessage( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam );
+ }
+ rDef = FALSE;
+ break;
+ case SAL_MSG_STARTTIMER:
+ ImplSalStartTimer( (sal_uLong) lParam, FALSE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_CREATEFRAME:
+ nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (sal_uLong)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RECREATEHWND:
+ nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, FALSE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RECREATECHILDHWND:
+ nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, TRUE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYFRAME:
+ delete (SalFrame*)lParam;
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYHWND:
+ //We only destroy the native window here. We do NOT destroy the SalFrame contained
+ //in the structure (GetWindowPtr()).
+ if (DestroyWindow((HWND)lParam) == 0)
+ {
+ OSL_ENSURE(0, "DestroyWindow failed!");
+ //Failure: We remove the SalFrame from the window structure. So we avoid that
+ // the window structure may contain an invalid pointer, once the SalFrame is deleted.
+ SetWindowPtr((HWND)lParam, 0);
+ }
+ rDef = FALSE;
+ break;
+ case SAL_MSG_CREATEOBJECT:
+ nRet = (LRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (WinSalFrame*)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_DESTROYOBJECT:
+ delete (SalObject*)lParam;
+ rDef = FALSE;
+ break;
+ case SAL_MSG_GETDC:
+ nRet = (LRESULT)GetDCEx( (HWND)wParam, 0, DCX_CACHE );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RELEASEDC:
+ ReleaseDC( (HWND)wParam, (HDC)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTTIMER:
+ SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam );
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ {
+ if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ }
+ return nRet;
+}
+
+LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ {
+ if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ }
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalInstance::AnyInput( sal_uInt16 nType )
+{
+ MSG aMsg;
+
+ if ( (nType & (INPUT_ANY)) == (INPUT_ANY) )
+ {
+ // revert bugfix for #108919# which never reported timeouts when called from the timer handler
+ // which made the application completely unresponsive during background formatting
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+ else
+ {
+ if ( nType & INPUT_MOUSE )
+ {
+ // Test for mouse input
+ if ( ImplPeekMessage( &aMsg, 0, WM_MOUSEFIRST, WM_MOUSELAST,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+
+ if ( nType & INPUT_KEYBOARD )
+ {
+ // Test for key input
+ if ( ImplPeekMessage( &aMsg, 0, WM_KEYDOWN, WM_KEYDOWN,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ {
+ if ( (aMsg.wParam == VK_SHIFT) ||
+ (aMsg.wParam == VK_CONTROL) ||
+ (aMsg.wParam == VK_MENU) )
+ return false;
+ else
+ return true;
+ }
+ }
+
+ if ( nType & INPUT_PAINT )
+ {
+ // Test for paint input
+ if ( ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, WM_SIZE, WM_SIZE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTCALLSIZE, SAL_MSG_POSTCALLSIZE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, WM_MOVE, WM_MOVE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTMOVE, SAL_MSG_POSTMOVE,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+
+ if ( nType & INPUT_TIMER )
+ {
+ // Test for timer input
+ if ( ImplPeekMessage( &aMsg, 0, WM_TIMER, WM_TIMER,
+ PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+
+ }
+
+ if ( nType & INPUT_OTHER )
+ {
+ // Test for any input
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
+ return true;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void SalTimer::Start( sal_uLong nMS )
+{
+ // Um auf Main-Thread umzuschalten
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstInstance )
+ {
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ else
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ }
+ else
+ ImplSalStartTimer( nMS, FALSE );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, sal_uLong nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle )
+{
+ // Um auf Main-Thread umzuschalten
+ HWND hWndParent;
+ if ( pParent )
+ hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
+ else
+ hWndParent = 0;
+ return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)hWndParent );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyFrame( SalFrame* pFrame )
+{
+ ImplSendMessage( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (LPARAM)pFrame );
+}
+
+// -----------------------------------------------------------------------
+
+SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
+ SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
+ sal_Bool /*bShow*/ )
+{
+ // Um auf Main-Thread umzuschalten
+ return (SalObject*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (LPARAM)static_cast<WinSalFrame*>(pParent) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyObject( SalObject* pObject )
+{
+ ImplSendMessage( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (LPARAM)pObject );
+}
+
+// -----------------------------------------------------------------------
+
+void* WinSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
+{
+ rReturnedBytes = 1;
+ rReturnedType = AsciiCString;
+ return const_cast<char *>("");
+}
+
+// -----------------------------------------------------------------------
+
+/** Add a file to the system shells recent document list if there is any.
+ This function may have no effect under Unix because there is no
+ standard API among the different desktop managers.
+
+ @param aFileUrl
+ The file url of the document.
+*/
+void WinSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
+{
+ rtl::OUString system_path;
+ osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path);
+
+ OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url");
+
+ if (osl::FileBase::E_None == rc)
+ SHAddToRecentDocs(SHARD_PATHW, system_path.getStr());
+}
+
+// -----------------------------------------------------------------------
+
+SalTimer* WinSalInstance::CreateSalTimer()
+{
+ return new WinSalTimer();
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* WinSalInstance::CreateSalBitmap()
+{
+ return new WinSalBitmap();
+}
+
+class WinImeStatus : public SalI18NImeStatus
+{
+ public:
+ WinImeStatus() {}
+ virtual ~WinImeStatus() {}
+
+ // asks whether there is a status window available
+ // to toggle into menubar
+ virtual bool canToggle() { return false; }
+ virtual void toggle() {}
+};
+
+SalI18NImeStatus* WinSalInstance::CreateI18NImeStatus()
+{
+ return new WinImeStatus();
+}
+
+// -----------------------------------------------------------------------
+
+const ::rtl::OUString& SalGetDesktopEnvironment()
+{
+ static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "Windows" ) );
+ return aDesktopEnvironment;
+}
+
+SalSession* WinSalInstance::CreateSalSession()
+{
+ return NULL;
+}
+
+#ifndef __MINGW32__
+// -----------------------------------------------------------------------
+int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo)
+{
+ // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
+ // Depending on this information we pass process violations directly to our signal handler ...
+ // and c++ (UNO) exceptions are sended to the following code on the current stack.
+ // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
+ // see also #112221#
+
+ static DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363;
+
+ if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ return UnhandledExceptionFilter( pExceptionInfo );
+}
+#endif
diff --git a/vcl/win/source/app/salshl.cxx b/vcl/win/source/app/salshl.cxx
new file mode 100755
index 000000000000..427f2092a0dc
--- /dev/null
+++ b/vcl/win/source/app/salshl.cxx
@@ -0,0 +1,165 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/debug.hxx>
+#include <tools/svwin.h>
+#include <win/saldata.hxx>
+
+// =======================================================================
+
+SalShlData aSalShlData;
+
+// =======================================================================
+
+#ifdef WNT
+
+extern "C"
+{
+
+#ifdef __MINGW32__
+sal_Bool WINAPI DllMain( HINSTANCE hInst, DWORD nReason, LPVOID pReserved )
+#else
+#ifdef ICC
+int _CRT_init(void);
+#else
+BOOL WINAPI _CRT_INIT( HINSTANCE hInst, DWORD nReason, LPVOID pReserved );
+#endif
+
+BOOL WINAPI LibMain( HINSTANCE hInst, DWORD nReason, LPVOID pReserved )
+#endif
+{
+ // Unsere DLL-Initialisierung
+ if ( nReason == DLL_PROCESS_ATTACH )
+ aSalShlData.mhInst = hInst;
+
+#ifndef __MINGW32__
+#ifdef ICC
+ if ( _CRT_init() == -1 )
+#else
+ if ( !_CRT_INIT( hInst, nReason, pReserved ) )
+#endif
+ return 0;
+#endif
+
+ return 1;
+}
+
+}
+
+#endif
+
+// =======================================================================
+
+HCURSOR ImplLoadSalCursor( int nId )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ HCURSOR hCursor = LoadCursor( aSalShlData.mhInst, MAKEINTRESOURCE( nId ) );
+
+ DBG_ASSERT( hCursor, "cursor not found in sal resource" );
+
+ return hCursor;
+}
+
+// -----------------------------------------------------------------------
+
+HBITMAP ImplLoadSalBitmap( int nId )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ HBITMAP hBitmap = LoadBitmap( aSalShlData.mhInst, MAKEINTRESOURCE( nId ) );
+
+ DBG_ASSERT( hBitmap, "bitmap not found in sal resource" );
+
+ return hBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon )
+{
+ DBG_ASSERT( aSalShlData.mhInst, "no DLL instance handle" );
+
+ SalData* pSalData = GetSalData();
+
+ // check the cache first
+ SalIcon *pSalIcon = pSalData->mpFirstIcon;
+ while( pSalIcon )
+ {
+ if( pSalIcon->nId != nId )
+ pSalIcon = pSalIcon->pNext;
+ else
+ {
+ rIcon = pSalIcon->hIcon;
+ rSmallIcon = pSalIcon->hSmallIcon;
+ return (rSmallIcon != 0);
+ }
+ }
+
+ // Try at first to load the icons from the application exe file
+ rIcon = (HICON)LoadImage( pSalData->mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXICON ), GetSystemMetrics( SM_CYICON ),
+ LR_DEFAULTCOLOR );
+ if ( !rIcon )
+ {
+ // If the application don't provide these icons, then we try
+ // to load the icon from the VCL resource
+ rIcon = (HICON)LoadImage( aSalShlData.mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXICON ), GetSystemMetrics( SM_CYICON ),
+ LR_DEFAULTCOLOR );
+ if ( rIcon )
+ {
+ rSmallIcon = (HICON)LoadImage( aSalShlData.mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
+ LR_DEFAULTCOLOR );
+ }
+ else
+ rSmallIcon = 0;
+ }
+ else
+ {
+ rSmallIcon = (HICON)LoadImage( pSalData->mhInst, MAKEINTRESOURCE( nId ),
+ IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
+ LR_DEFAULTCOLOR );
+ }
+
+ if( rIcon )
+ {
+ // add to icon cache
+ pSalIcon = new SalIcon();
+ pSalIcon->nId = nId;
+ pSalIcon->hIcon = rIcon;
+ pSalIcon->hSmallIcon = rSmallIcon;
+ pSalIcon->pNext = pSalData->mpFirstIcon;
+ pSalData->mpFirstIcon = pSalIcon;
+ }
+
+ return (rSmallIcon != 0);
+}
diff --git a/vcl/win/source/app/saltimer.cxx b/vcl/win/source/app/saltimer.cxx
new file mode 100755
index 000000000000..f0b88a8e381c
--- /dev/null
+++ b/vcl/win/source/app/saltimer.cxx
@@ -0,0 +1,154 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/svwin.h>
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+#include <win/saldata.hxx>
+#include <win/saltimer.h>
+#include <win/salinst.h>
+
+// =======================================================================
+
+// Maximale Periode
+#define MAX_SYSPERIOD 65533
+
+// =======================================================================
+
+void ImplSalStartTimer( sal_uLong nMS, sal_Bool bMutex )
+{
+ SalData* pSalData = GetSalData();
+
+ // Remenber the time of the timer
+ pSalData->mnTimerMS = nMS;
+ if ( !bMutex )
+ pSalData->mnTimerOrgMS = nMS;
+
+ // Periode darf nicht zu gross sein, da Windows mit sal_uInt16 arbeitet
+ if ( nMS > MAX_SYSPERIOD )
+ nMS = MAX_SYSPERIOD;
+
+ // Gibt es einen Timer, dann zerstoren
+ if ( pSalData->mnTimerId )
+ KillTimer( 0, pSalData->mnTimerId );
+
+ // Make a new timer with new period
+ pSalData->mnTimerId = SetTimer( 0, 0, (UINT)nMS, SalTimerProc );
+ pSalData->mnNextTimerTime = pSalData->mnLastEventTime + nMS;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalTimer::~WinSalTimer()
+{
+}
+
+void WinSalTimer::Start( sal_uLong nMS )
+{
+ // switch to main thread
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mpFirstInstance )
+ {
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ else
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
+ }
+ else
+ ImplSalStartTimer( nMS, FALSE );
+}
+
+void WinSalTimer::Stop()
+{
+ SalData* pSalData = GetSalData();
+
+ // If we have a timer, than
+ if ( pSalData->mnTimerId )
+ {
+ KillTimer( 0, pSalData->mnTimerId );
+ pSalData->mnTimerId = 0;
+ pSalData->mnNextTimerTime = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void CALLBACK SalTimerProc( HWND, UINT, UINT_PTR nId, DWORD )
+{
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ SalData* pSalData = GetSalData();
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // Test for MouseLeave
+ SalTestMouseLeave();
+
+ bool bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ // Try to aquire the mutex. If we don't get the mutex then we
+ // try this a short time later again.
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ bRecursive = pSalData->mbInTimerProc && (nId != SALTIMERPROC_RECURSIVE);
+ if ( pSVData->mpSalTimer && ! bRecursive )
+ {
+ pSalData->mbInTimerProc = TRUE;
+ pSVData->mpSalTimer->CallCallback();
+ pSalData->mbInTimerProc = FALSE;
+ ImplSalYieldMutexRelease();
+
+ // Run the timer in the correct time, if we start this
+ // with a small timeout, because we don't get the mutex
+ if ( pSalData->mnTimerId &&
+ (pSalData->mnTimerMS != pSalData->mnTimerOrgMS) )
+ ImplSalStartTimer( pSalData->mnTimerOrgMS, FALSE );
+ }
+ }
+ else
+ ImplSalStartTimer( 10, TRUE );
+ }
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+}
diff --git a/vcl/win/source/gdi/salbmp.cxx b/vcl/win/source/gdi/salbmp.cxx
new file mode 100755
index 000000000000..3dc176ae23b8
--- /dev/null
+++ b/vcl/win/source/gdi/salbmp.cxx
@@ -0,0 +1,636 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/svwin.h>
+
+#include <vcl/bitmap.hxx> // for BitmapSystemData
+#include <vcl/salbtype.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/salgdi.h>
+#include <win/saldata.hxx>
+#include <win/salbmp.h>
+
+#include <string.h>
+
+// -----------
+// - Inlines -
+// -----------
+
+inline void ImplSetPixel4( const HPBYTE pScanline, long nX, const BYTE cIndex )
+{
+ BYTE& rByte = pScanline[ nX >> 1 ];
+
+ ( nX & 1 ) ? ( rByte &= 0xf0, rByte |= ( cIndex & 0x0f ) ) :
+ ( rByte &= 0x0f, rByte |= ( cIndex << 4 ) );
+}
+
+// ----------------
+// - WinSalBitmap -
+// ----------------
+
+WinSalBitmap::WinSalBitmap() :
+ mhDIB ( 0 ),
+ mhDDB ( 0 ),
+ mnBitCount ( 0 )
+{
+}
+
+// ------------------------------------------------------------------
+
+WinSalBitmap::~WinSalBitmap()
+{
+ Destroy();
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle )
+{
+ bool bRet = TRUE;
+
+ if( bDIB )
+ mhDIB = (HGLOBAL) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, TRUE ) : hBitmap );
+ else
+ mhDDB = (HBITMAP) ( bCopyHandle ? ImplCopyDIBOrDDB( hBitmap, FALSE ) : hBitmap );
+
+ if( mhDIB )
+ {
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) GlobalLock( mhDIB );
+
+ maSize = Size( pBIH->biWidth, pBIH->biHeight );
+ mnBitCount = pBIH->biBitCount;
+
+ if( mnBitCount )
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 : ( mnBitCount <= 4 ) ? 4 : ( mnBitCount <= 8 ) ? 8 : 24;
+
+ GlobalUnlock( mhDIB );
+ }
+ else if( mhDDB )
+ {
+ BITMAP aDDBInfo;
+
+ if( WIN_GetObject( mhDDB, sizeof( BITMAP ), &aDDBInfo ) )
+ {
+ maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
+ mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
+
+ if( mnBitCount )
+ {
+ mnBitCount = ( mnBitCount <= 1 ) ? 1 :
+ ( mnBitCount <= 4 ) ? 4 :
+ ( mnBitCount <= 8 ) ? 8 : 24;
+ }
+ }
+ else
+ {
+ mhDDB = 0;
+ bRet = FALSE;
+ }
+ }
+ else
+ bRet = FALSE;
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal )
+{
+ bool bRet = FALSE;
+
+ mhDIB = ImplCreateDIB( rSize, nBitCount, rPal );
+
+ if( mhDIB )
+ {
+ maSize = rSize;
+ mnBitCount = nBitCount;
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBitmap )
+{
+ bool bRet = FALSE;
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+
+ if ( rSalBitmap.mhDIB || rSalBitmap.mhDDB )
+ {
+ HANDLE hNewHdl = ImplCopyDIBOrDDB( rSalBitmap.mhDIB ? rSalBitmap.mhDIB : rSalBitmap.mhDDB,
+ rSalBitmap.mhDIB != 0 );
+
+ if ( hNewHdl )
+ {
+ if( rSalBitmap.mhDIB )
+ mhDIB = (HGLOBAL) hNewHdl;
+ else if( rSalBitmap.mhDDB )
+ mhDDB = (HBITMAP) hNewHdl;
+
+ maSize = rSalBitmap.maSize;
+ mnBitCount = rSalBitmap.mnBitCount;
+
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, SalGraphics* pSGraphics )
+{
+ bool bRet = FALSE;
+
+ const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
+ WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
+
+ if( rSalBmp.mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( rSalBmp.mhDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+ HDC hDC = pGraphics->mhDC;
+ HBITMAP hNewDDB;
+ BITMAP aDDBInfo;
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ ImplGetDIBColorCount( rSalBmp.mhDIB ) * sizeof( RGBQUAD );
+
+ if( pBIH->biBitCount == 1 )
+ {
+ hNewDDB = CreateBitmap( pBIH->biWidth, pBIH->biHeight, 1, 1, NULL );
+
+ if( hNewDDB )
+ SetDIBits( hDC, hNewDDB, 0, pBIH->biHeight, pBits, pBI, DIB_RGB_COLORS );
+ }
+ else
+ hNewDDB = CreateDIBitmap( hDC, (PBITMAPINFOHEADER) pBI, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
+
+ GlobalUnlock( rSalBmp.mhDIB );
+
+ if( hNewDDB && WIN_GetObject( hNewDDB, sizeof( BITMAP ), &aDDBInfo ) )
+ {
+ mhDDB = hNewDDB;
+ maSize = Size( aDDBInfo.bmWidth, aDDBInfo.bmHeight );
+ mnBitCount = aDDBInfo.bmPlanes * aDDBInfo.bmBitsPixel;
+
+ bRet = TRUE;
+ }
+ else if( hNewDDB )
+ DeleteObject( hNewDDB );
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+bool WinSalBitmap::Create( const SalBitmap& rSSalBmp, sal_uInt16 nNewBitCount )
+{
+ bool bRet = FALSE;
+
+ const WinSalBitmap& rSalBmp = static_cast<const WinSalBitmap&>(rSSalBmp);
+
+ if( rSalBmp.mhDDB )
+ {
+ mhDIB = ImplCreateDIB( rSalBmp.maSize, nNewBitCount, BitmapPalette() );
+
+ if( mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ const int nLines = (int) rSalBmp.maSize.Height();
+ HDC hDC = GetDC( 0 );
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ ImplGetDIBColorCount( mhDIB ) * sizeof( RGBQUAD );
+ SalData* pSalData = GetSalData();
+ HPALETTE hOldPal = 0;
+
+ if ( pSalData->mhDitherPal )
+ {
+ hOldPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+
+ if( GetDIBits( hDC, rSalBmp.mhDDB, 0, nLines, pBits, pBI, DIB_RGB_COLORS ) == nLines )
+ {
+ GlobalUnlock( mhDIB );
+ maSize = rSalBmp.maSize;
+ mnBitCount = nNewBitCount;
+ bRet = TRUE;
+ }
+ else
+ {
+ GlobalUnlock( mhDIB );
+ GlobalFree( mhDIB );
+ mhDIB = 0;
+ }
+
+ if( hOldPal )
+ SelectPalette( hDC, hOldPal, TRUE );
+
+ ReleaseDC( 0, hDC );
+ }
+ }
+
+ return bRet;
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::Destroy()
+{
+ if( mhDIB )
+ GlobalFree( mhDIB );
+ else if( mhDDB )
+ DeleteObject( mhDDB );
+
+ maSize = Size();
+ mnBitCount = 0;
+}
+
+// ------------------------------------------------------------------
+
+sal_uInt16 WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB )
+{
+ sal_uInt16 nColors = 0;
+
+ if( hDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ if ( pBIH->biSize != sizeof( BITMAPCOREHEADER ) )
+ {
+ if( pBIH->biBitCount <= 8 )
+ {
+ if ( pBIH->biClrUsed )
+ nColors = (sal_uInt16) pBIH->biClrUsed;
+ else
+ nColors = 1 << pBIH->biBitCount;
+ }
+ }
+ else if( ( (PBITMAPCOREHEADER) pBI )->bcBitCount <= 8 )
+ nColors = 1 << ( (PBITMAPCOREHEADER) pBI )->bcBitCount;
+
+ GlobalUnlock( hDIB );
+ }
+
+ return nColors;
+}
+
+// ------------------------------------------------------------------
+
+HGLOBAL WinSalBitmap::ImplCreateDIB( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rPal )
+{
+ DBG_ASSERT( nBits == 1 || nBits == 4 || nBits == 8 || nBits == 16 || nBits == 24, "Unsupported BitCount!" );
+
+ HGLOBAL hDIB = 0;
+
+ if ( rSize.Width() && rSize.Height() )
+ {
+ const sal_uLong nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height();
+ const sal_uInt16 nColors = ( nBits <= 8 ) ? ( 1 << nBits ) : 0;
+
+ hDIB = GlobalAlloc( GHND, sizeof( BITMAPINFOHEADER ) + nColors * sizeof( RGBQUAD ) + nImageSize );
+
+ if( hDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ pBIH->biSize = sizeof( BITMAPINFOHEADER );
+ pBIH->biWidth = rSize.Width();
+ pBIH->biHeight = rSize.Height();
+ pBIH->biPlanes = 1;
+ pBIH->biBitCount = nBits;
+ pBIH->biCompression = BI_RGB;
+ pBIH->biSizeImage = nImageSize;
+ pBIH->biXPelsPerMeter = 0;
+ pBIH->biYPelsPerMeter = 0;
+ pBIH->biClrUsed = 0;
+ pBIH->biClrImportant = 0;
+
+ if ( nColors )
+ {
+ const sal_uInt16 nMinCount = Min( nColors, rPal.GetEntryCount() );
+
+ if( nMinCount )
+ memcpy( pBI->bmiColors, rPal.ImplGetColorBuffer(), nMinCount * sizeof( RGBQUAD ) );
+ }
+
+ GlobalUnlock( hDIB );
+ }
+ }
+
+ return hDIB;
+}
+
+// ------------------------------------------------------------------
+
+HANDLE WinSalBitmap::ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB )
+{
+ HANDLE hCopy = 0;
+
+ if ( bDIB && hHdl )
+ {
+ const sal_uLong nSize = GlobalSize( hHdl );
+
+ if ( (hCopy = GlobalAlloc( GHND, nSize )) != 0 )
+ {
+ memcpy( (LPSTR) GlobalLock( hCopy ), (LPSTR) GlobalLock( hHdl ), nSize );
+
+ GlobalUnlock( hCopy );
+ GlobalUnlock( hHdl );
+ }
+ }
+ else if ( hHdl )
+ {
+ BITMAP aBmp;
+
+ // Source-Bitmap nach Groesse befragen
+ WIN_GetObject( hHdl, sizeof( BITMAP ), (LPSTR) &aBmp );
+
+ // Destination-Bitmap erzeugen
+ if ( (hCopy = CreateBitmapIndirect( &aBmp )) != 0 )
+ {
+ HDC hBmpDC = CreateCompatibleDC( 0 );
+ HBITMAP hBmpOld = (HBITMAP) SelectObject( hBmpDC, hHdl );
+ HDC hCopyDC = CreateCompatibleDC( hBmpDC );
+ HBITMAP hCopyOld = (HBITMAP) SelectObject( hCopyDC, hCopy );
+
+ BitBlt( hCopyDC, 0, 0, aBmp.bmWidth, aBmp.bmHeight, hBmpDC, 0, 0, SRCCOPY );
+
+ SelectObject( hCopyDC, hCopyOld );
+ DeleteDC( hCopyDC );
+
+ SelectObject( hBmpDC, hBmpOld );
+ DeleteDC( hBmpDC );
+ }
+ }
+
+ return hCopy;
+}
+
+// ------------------------------------------------------------------
+
+BitmapBuffer* WinSalBitmap::AcquireBuffer( bool /*bReadOnly*/ )
+{
+ BitmapBuffer* pBuffer = NULL;
+
+ if( mhDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+
+ if( ( pBIH->biCompression == BI_RLE4 ) || ( pBIH->biCompression == BI_RLE8 ) )
+ {
+ Size aSizePix( pBIH->biWidth, pBIH->biHeight );
+ HGLOBAL hNewDIB = ImplCreateDIB( aSizePix, pBIH->biBitCount, BitmapPalette() );
+
+ if( hNewDIB )
+ {
+ PBITMAPINFO pNewBI = (PBITMAPINFO) GlobalLock( hNewDIB );
+ PBITMAPINFOHEADER pNewBIH = (PBITMAPINFOHEADER) pNewBI;
+ const sal_uInt16 nColorCount = ImplGetDIBColorCount( hNewDIB );
+ const sal_uLong nOffset = *(DWORD*) pBI + nColorCount * sizeof( RGBQUAD );
+ BYTE* pOldBits = (PBYTE) pBI + nOffset;
+ BYTE* pNewBits = (PBYTE) pNewBI + nOffset;
+
+ memcpy( pNewBI, pBI, nOffset );
+ pNewBIH->biCompression = 0;
+ ImplDecodeRLEBuffer( pOldBits, pNewBits, aSizePix, pBIH->biCompression == BI_RLE4 );
+
+ GlobalUnlock( mhDIB );
+ GlobalFree( mhDIB );
+ mhDIB = hNewDIB;
+ pBI = pNewBI;
+ pBIH = pNewBIH;
+ }
+ }
+
+ if( pBIH->biPlanes == 1 )
+ {
+ pBuffer = new BitmapBuffer;
+
+ pBuffer->mnFormat = BMP_FORMAT_BOTTOM_UP |
+ ( pBIH->biBitCount == 1 ? BMP_FORMAT_1BIT_MSB_PAL :
+ pBIH->biBitCount == 4 ? BMP_FORMAT_4BIT_MSN_PAL :
+ pBIH->biBitCount == 8 ? BMP_FORMAT_8BIT_PAL :
+ pBIH->biBitCount == 16 ? BMP_FORMAT_16BIT_TC_LSB_MASK :
+ pBIH->biBitCount == 24 ? BMP_FORMAT_24BIT_TC_BGR :
+ pBIH->biBitCount == 32 ? BMP_FORMAT_32BIT_TC_MASK : 0UL );
+
+ if( BMP_SCANLINE_FORMAT( pBuffer->mnFormat ) )
+ {
+ pBuffer->mnWidth = maSize.Width();
+ pBuffer->mnHeight = maSize.Height();
+ pBuffer->mnScanlineSize = AlignedWidth4Bytes( maSize.Width() * pBIH->biBitCount );
+ pBuffer->mnBitCount = (sal_uInt16) pBIH->biBitCount;
+
+ if( pBuffer->mnBitCount <= 8 )
+ {
+ const sal_uInt16 nPalCount = ImplGetDIBColorCount( mhDIB );
+
+ pBuffer->maPalette.SetEntryCount( nPalCount );
+ memcpy( pBuffer->maPalette.ImplGetColorBuffer(), pBI->bmiColors, nPalCount * sizeof( RGBQUAD ) );
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nPalCount * sizeof( RGBQUAD );
+ }
+ else if( ( pBIH->biBitCount == 16 ) || ( pBIH->biBitCount == 32 ) )
+ {
+ sal_uLong nOffset = 0UL;
+
+ if( pBIH->biCompression == BI_BITFIELDS )
+ {
+ nOffset = 3 * sizeof( RGBQUAD );
+ pBuffer->maColorMask = ColorMask( *(UINT32*) &pBI->bmiColors[ 0 ],
+ *(UINT32*) &pBI->bmiColors[ 1 ],
+ *(UINT32*) &pBI->bmiColors[ 2 ] );
+ }
+ else if( pBIH->biBitCount == 16 )
+ pBuffer->maColorMask = ColorMask( 0x00007c00UL, 0x000003e0UL, 0x0000001fUL );
+ else
+ pBuffer->maColorMask = ColorMask( 0x00ff0000UL, 0x0000ff00UL, 0x000000ffUL );
+
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI + nOffset;
+ }
+ else
+ pBuffer->mpBits = (PBYTE) pBI + *(DWORD*) pBI;
+ }
+ else
+ {
+ GlobalUnlock( mhDIB );
+ delete pBuffer;
+ pBuffer = NULL;
+ }
+ }
+ else
+ GlobalUnlock( mhDIB );
+ }
+
+ return pBuffer;
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly )
+{
+ if( pBuffer )
+ {
+ if( mhDIB )
+ {
+ if( !bReadOnly && !!pBuffer->maPalette )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( mhDIB );
+ const sal_uInt16 nCount = pBuffer->maPalette.GetEntryCount();
+ const sal_uInt16 nDIBColorCount = ImplGetDIBColorCount( mhDIB );
+ memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), Min( nDIBColorCount, nCount ) * sizeof( RGBQUAD ) );
+ GlobalUnlock( mhDIB );
+ }
+
+ GlobalUnlock( mhDIB );
+ }
+
+ delete pBuffer;
+ }
+}
+
+// ------------------------------------------------------------------
+
+void WinSalBitmap::ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf,
+ const Size& rSizePixel, bool bRLE4 )
+{
+ HPBYTE pRLE = (HPBYTE) pSrcBuf;
+ HPBYTE pDIB = (HPBYTE) pDstBuf;
+ HPBYTE pRow = (HPBYTE) pDstBuf;
+ sal_uLong nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) );
+ HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1;
+ sal_uLong nCountByte;
+ sal_uLong nRunByte;
+ sal_uLong nX = 0;
+ sal_uLong i;
+ BYTE cTmp;
+ bool bEndDecoding = FALSE;
+
+ if( pRLE && pDIB )
+ {
+ do
+ {
+ if( ( nCountByte = *pRLE++ ) == 0 )
+ {
+ nRunByte = *pRLE++;
+
+ if( nRunByte > 2UL )
+ {
+ if( bRLE4 )
+ {
+ nCountByte = nRunByte >> 1UL;
+
+ for( i = 0; i < nCountByte; i++ )
+ {
+ cTmp = *pRLE++;
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nRunByte & 1 )
+ ImplSetPixel4( pDIB, nX++, *pRLE++ >> 4 );
+
+ if( ( ( nRunByte + 1 ) >> 1 ) & 1 )
+ pRLE++;
+ }
+ else
+ {
+ memcpy( &pDIB[ nX ], pRLE, nRunByte );
+ pRLE += nRunByte;
+ nX += nRunByte;
+
+ if( nRunByte & 1 )
+ pRLE++;
+ }
+ }
+ else if( !nRunByte )
+ {
+ pDIB = ( pRow += nWidthAl );
+ nX = 0UL;
+ }
+ else if( nRunByte == 1 )
+ bEndDecoding = TRUE;
+ else
+ {
+ nX += *pRLE++;
+ pDIB = ( pRow += ( *pRLE++ ) * nWidthAl );
+ }
+ }
+ else
+ {
+ cTmp = *pRLE++;
+
+ if( bRLE4 )
+ {
+ nRunByte = nCountByte >> 1;
+
+ for( i = 0; i < nRunByte; i++ )
+ {
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ ImplSetPixel4( pDIB, nX++, cTmp & 0x0f );
+ }
+
+ if( nCountByte & 1 )
+ ImplSetPixel4( pDIB, nX++, cTmp >> 4 );
+ }
+ else
+ {
+ for( i = 0; i < nCountByte; i++ )
+ pDIB[ nX++ ] = cTmp;
+ }
+ }
+ }
+ while( !bEndDecoding && ( pDIB <= pLast ) );
+ }
+}
+
+bool WinSalBitmap::GetSystemData( BitmapSystemData& rData )
+{
+ bool bRet = false;
+ if( mhDIB || mhDDB )
+ {
+ bRet = true;
+ rData.pDIB = mhDIB;
+ rData.pDDB = mhDDB;
+ const Size& rSize = GetSize ();
+ rData.mnWidth = rSize.Width();
+ rData.mnHeight = rSize.Height();
+ }
+ return bRet;
+}
diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx
new file mode 100644
index 000000000000..bc2f8ade3ccc
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi.cxx
@@ -0,0 +1,1826 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <rtl/strbuf.hxx>
+
+#include <tools/svwin.h>
+#include <tools/debug.hxx>
+#include <tools/poly.hxx>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salgdi.h>
+#include <win/salframe.h>
+
+#include <region.h>
+
+using namespace rtl;
+
+// =======================================================================
+
+// comment out to prevent use of beziers on GDI functions
+#define USE_GDI_BEZIERS
+
+// =======================================================================
+
+#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])
+
+// =======================================================================
+
+struct SysColorEntry
+{
+ DWORD nRGB;
+ SysColorEntry* pNext;
+};
+
+// =======================================================================
+
+static SysColorEntry* pFirstSysColor = NULL;
+static SysColorEntry* pActSysColor = NULL;
+
+// -----------------------------------------------------------------------------
+
+// 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 }
+};
+
+// -----------------------------------------------------------------------------
+
+static BYTE aOrdDither8Bit[8][8] =
+{
+ 0, 38, 9, 48, 2, 40, 12, 50,
+ 25, 12, 35, 22, 28, 15, 37, 24,
+ 6, 44, 3, 41, 8, 47, 5, 44,
+ 32, 19, 28, 16, 34, 21, 31, 18,
+ 1, 40, 11, 49, 0, 39, 10, 48,
+ 27, 14, 36, 24, 26, 13, 36, 23,
+ 8, 46, 4, 43, 7, 45, 4, 42,
+ 33, 20, 30, 17, 32, 20, 29, 16
+};
+
+// -----------------------------------------------------------------------------
+
+static BYTE aOrdDither16Bit[8][8] =
+{
+ 0, 6, 1, 7, 0, 6, 1, 7,
+ 4, 2, 5, 3, 4, 2, 5, 3,
+ 1, 7, 0, 6, 1, 7, 0, 6,
+ 5, 3, 4, 2, 5, 3, 4, 2,
+ 0, 6, 1, 7, 0, 6, 1, 7,
+ 4, 2, 5, 3, 4, 2, 5, 3,
+ 1, 7, 0, 6, 1, 7, 0, 6,
+ 5, 3, 4, 2, 5, 3, 4, 2
+};
+
+// =======================================================================
+
+// Pens muessen wir mit 1 Pixel-Breite erzeugen, da ansonsten die S3-Karte
+// viele Paintprobleme hat, wenn Polygone/PolyLines gezeichnet werden und
+// eine komplexe ClipRegion gesetzt ist
+#define GSL_PEN_WIDTH 1
+
+// =======================================================================
+
+#define SAL_POLYPOLYCOUNT_STACKBUF 8
+#define SAL_POLYPOLYPOINTS_STACKBUF 64
+
+// =======================================================================
+
+void ImplInitSalGDI()
+{
+ SalData* pSalData = GetSalData();
+
+ // 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 cache of device contexts
+ pSalData->mpHDCCache = new HDCCache[ CACHESIZE_HDC ];
+ memset( pSalData->mpHDCCache, 0, CACHESIZE_HDC * sizeof( HDCCache ) );
+
+ // initialize temporary font list
+ pSalData->mpTempFontItem = NULL;
+
+ // support palettes for 256 color displays
+ HDC hDC = GetDC( 0 );
+ 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 = (HBITMAP) ::SelectObject( hMemDC, hMemBmp );
+ HBRUSH hMemBrush = ::CreateSolidBrush( PALETTERGB( 175, 171, 169 ) );
+ HBRUSH hBrushOld = (HBRUSH) ::SelectObject( hMemDC, hMemBrush );
+ sal_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
+ long n;
+
+ pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, sizeof( BITMAPINFOHEADER ) + 192 );
+ pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
+ pSalData->mpDitherDiff = new long[ 256 ];
+ pSalData->mpDitherLow = new BYTE[ 256 ];
+ pSalData->mpDitherHigh = new BYTE[ 256 ];
+ pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER );
+ memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
+
+ BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
+
+ pBIH->biSize = sizeof( BITMAPINFOHEADER );
+ pBIH->biWidth = 8;
+ pBIH->biHeight = 8;
+ pBIH->biPlanes = 1;
+ pBIH->biBitCount = 24;
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherDiff[ n ] = n - ( n & 248L );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherLow[ n ] = (BYTE) ( n & 248 );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherHigh[ n ] = (BYTE) Min( pSalData->mpDitherLow[ n ] + 8L, 255L );
+ }
+ }
+ 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 = (LOGPALETTE*) new char[ sizeof( LOGPALETTE ) + ( nTotalCount * sizeof( PALETTEENTRY ) ) ];
+ pLogPal->palVersion = 0x0300;
+ pLogPal->palNumEntries = (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[] (char*) pLogPal;
+
+ if( pSalData->mhDitherPal )
+ {
+ // create DIBPattern for 8Bit dithering
+ long nSize = sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) ) + 64;
+ long n;
+
+ pSalData->mhDitherDIB = GlobalAlloc( GMEM_FIXED, nSize );
+ pSalData->mpDitherDIB = (BYTE*) GlobalLock( pSalData->mhDitherDIB );
+ pSalData->mpDitherDiff = new long[ 256 ];
+ pSalData->mpDitherLow = new BYTE[ 256 ];
+ pSalData->mpDitherHigh = new BYTE[ 256 ];
+ pSalData->mpDitherDIBData = pSalData->mpDitherDIB + sizeof( BITMAPINFOHEADER ) + ( 256 * sizeof( short ) );
+ memset( pSalData->mpDitherDIB, 0, sizeof( BITMAPINFOHEADER ) );
+
+ BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*) pSalData->mpDitherDIB;
+ short* pColors = (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 ] = (short)( n + DITHER_MAX_SYSCOLOR );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherDiff[ n ] = n % 51L;
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherLow[ n ] = (BYTE) ( n / 51L );
+
+ for( n = 0; n < 256L; n++ )
+ pSalData->mpDitherHigh[ n ] = (BYTE)Min( pSalData->mpDitherLow[ n ] + 1, 5 );
+ }
+
+ // get system color entries
+ ImplUpdateSysColorEntries();
+ }
+
+ ReleaseDC( 0, hDC );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplFreeSalGDI()
+{
+ SalData* pSalData = GetSalData();
+
+ // 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] );
+
+ // 50% Brush loeschen
+ if ( pSalData->mh50Brush )
+ {
+ DeleteBrush( pSalData->mh50Brush );
+ pSalData->mh50Brush = 0;
+ }
+
+ // 50% Bitmap loeschen
+ if ( pSalData->mh50Bmp )
+ {
+ DeleteBitmap( pSalData->mh50Bmp );
+ pSalData->mh50Bmp = 0;
+ }
+
+ ImplClearHDCCache( pSalData );
+ delete[] pSalData->mpHDCCache;
+
+ // Ditherpalette loeschen, wenn vorhanden
+ if ( pSalData->mhDitherPal )
+ {
+ DeleteObject( pSalData->mhDitherPal );
+ pSalData->mhDitherPal = 0;
+ }
+
+ // delete buffers for dithering DIB patterns, if neccessary
+ if ( pSalData->mhDitherDIB )
+ {
+ GlobalUnlock( pSalData->mhDitherDIB );
+ GlobalFree( pSalData->mhDitherDIB );
+ pSalData->mhDitherDIB = 0;
+ delete[] pSalData->mpDitherDiff;
+ delete[] pSalData->mpDitherLow;
+ delete[] pSalData->mpDitherHigh;
+ }
+
+ // delete SysColorList
+ SysColorEntry* pEntry = pFirstSysColor;
+ while( pEntry )
+ {
+ SysColorEntry* pTmp = pEntry->pNext;
+ delete pEntry;
+ pEntry = pTmp;
+ }
+ pFirstSysColor = NULL;
+
+ // delete icon cache
+ SalIcon* pIcon = pSalData->mpFirstIcon;
+ pSalData->mpFirstIcon = NULL;
+ while( pIcon )
+ {
+ SalIcon* pTmp = pIcon->pNext;
+ DestroyIcon( pIcon->hIcon );
+ DestroyIcon( pIcon->hSmallIcon );
+ delete pIcon;
+ pIcon = pTmp;
+ }
+
+ // delete temporary font list
+ ImplReleaseTempFonts( *pSalData );
+}
+
+// -----------------------------------------------------------------------
+
+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;
+}
+
+// =======================================================================
+
+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 );
+
+ if ( !ImplIsPaletteEntry( GetRValue( nRGB ), GetGValue( nRGB ), GetBValue( nRGB ) ) )
+ {
+ if ( !pFirstSysColor )
+ {
+ pActSysColor = pFirstSysColor = new SysColorEntry;
+ pFirstSysColor->nRGB = nRGB;
+ pFirstSysColor->pNext = NULL;
+ }
+ else
+ {
+ pActSysColor = pActSysColor->pNext = new SysColorEntry;
+ pActSysColor->nRGB = nRGB;
+ pActSysColor->pNext = NULL;
+ }
+ }
+}
+
+// =======================================================================
+
+void ImplUpdateSysColorEntries()
+{
+ // delete old SysColorList
+ SysColorEntry* pEntry = pFirstSysColor;
+ while( pEntry )
+ {
+ SysColorEntry* pTmp = pEntry->pNext;
+ delete pEntry;
+ pEntry = pTmp;
+ }
+ pActSysColor = pFirstSysColor = NULL;
+
+ // create new sys color list
+ ImplInsertSysColorEntry( COLOR_ACTIVEBORDER );
+ ImplInsertSysColorEntry( COLOR_INACTIVEBORDER );
+ if( aSalShlData.mnVersion >= 410 )
+ {
+ 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 );
+}
+
+// -----------------------------------------------------------------------
+
+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 )
+{
+ // Beim Printer berechnen wir die minimale Linienstaerke
+ if ( pData->mbPrinter )
+ {
+ int nDPIX = GetDeviceCaps( pData->mhDC, LOGPIXELSX );
+ if ( nDPIX <= 300 )
+ pData->mnPenWidth = 0;
+ else
+ pData->mnPenWidth = nDPIX/300;
+ }
+
+ ::SetTextAlign( pData->mhDC, TA_BASELINE | TA_LEFT | TA_NOUPDATECP );
+ ::SetBkMode( pData->mhDC, TRANSPARENT );
+ ::SetROP2( pData->mhDC, R2_COPYPEN );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalDeInitGraphics( WinSalGraphics* pData )
+{
+ // clear clip region
+ SelectClipRgn( pData->mhDC, 0 );
+ // select default objects
+ if ( pData->mhDefPen )
+ SelectPen( pData->mhDC, pData->mhDefPen );
+ if ( pData->mhDefBrush )
+ SelectBrush( pData->mhDC, pData->mhDefBrush );
+ if ( pData->mhDefFont )
+ SelectFont( pData->mhDC, pData->mhDefFont );
+}
+
+// =======================================================================
+
+HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp )
+{
+ SalData* pSalData = GetSalData();
+ HDCCache* pC = &pSalData->mpHDCCache[ nID ];
+
+ if( !pC->mhDC )
+ {
+ HDC hDC = GetDC( 0 );
+
+ // neuen DC mit DefaultBitmap anlegen
+ 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 = (HBITMAP) SelectObject( pC->mhDC, pC->mhSelBmp );
+
+ ReleaseDC( 0, hDC );
+ }
+
+ if ( hBmp )
+ SelectObject( pC->mhDC, pC->mhActBmp = hBmp );
+ else
+ pC->mhActBmp = 0;
+
+ return pC->mhDC;
+}
+
+// =======================================================================
+
+void ImplReleaseCachedDC( sal_uLong nID )
+{
+ SalData* pSalData = GetSalData();
+ HDCCache* pC = &pSalData->mpHDCCache[ 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->mpHDCCache[ i ];
+
+ if( pC->mhDC )
+ {
+ SelectObject( pC->mhDC, pC->mhDefBmp );
+
+ if( pC->mhDefPal )
+ SelectPalette( pC->mhDC, pC->mhDefPal, TRUE );
+
+ DeleteDC( pC->mhDC );
+ DeleteObject( pC->mhSelBmp );
+ }
+ }
+}
+
+// =======================================================================
+
+// #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_uLong* pPoints,
+ const SalPoint* const* pPtAry,
+ const BYTE* const* pFlgAry,
+ POINT* pWinPointAry,
+ BYTE* pWinFlagAry )
+{
+ sal_uLong nCurrPoly;
+ for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly )
+ {
+ const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ );
+ const BYTE* pCurrFlag = *pFlgAry++;
+ const sal_uLong nCurrPoints = *pPoints++;
+ const bool bHaveFlagArray( pCurrFlag );
+ sal_uLong nCurrPoint;
+
+ if( nCurrPoints )
+ {
+ // start figure
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_MOVETO;
+ ++pCurrFlag;
+
+ for( nCurrPoint=1; nCurrPoint<nCurrPoints; )
+ {
+ // #102067# Check existence of flag array
+ if( bHaveFlagArray &&
+ ( nCurrPoint + 2 ) < nCurrPoints )
+ {
+ BYTE P4( pCurrFlag[ 2 ] );
+
+ if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) &&
+ ( POLY_CONTROL == pCurrFlag[ 1 ] ) &&
+ ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) )
+ {
+ // control point one
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ // control point two
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ // end point
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_BEZIERTO;
+
+ nCurrPoint += 3;
+ pCurrFlag += 3;
+ continue;
+ }
+ }
+
+ // regular line point
+ *pWinPointAry++ = *pCurrPoint++;
+ *pWinFlagAry++ = PT_LINETO;
+ ++pCurrFlag;
+ ++nCurrPoint;
+ }
+
+ // end figure?
+ if( bCloseFigures )
+ pWinFlagAry[-1] |= PT_CLOSEFIGURE;
+ }
+ }
+}
+
+// =======================================================================
+
+// #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; i<nPoints; ++i, ++pPtAry, ++pFlgAry )
+ {
+ if( *pFlgAry != POLY_CONTROL )
+ {
+ LineTo( hdc, pPtAry->mnX, pPtAry->mnY );
+ }
+ else if( nPoints - i > 2 )
+ {
+ PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 );
+ i += 2; pPtAry += 2; pFlgAry += 2;
+ }
+ }
+ }
+}
+
+// =======================================================================
+
+WinSalGraphics::WinSalGraphics()
+{
+ for( int i = 0; i < MAX_FALLBACK; ++i )
+ {
+ mhFonts[ i ] = 0;
+ mpWinFontData[ i ] = NULL;
+ mpWinFontEntry[ i ] = NULL;
+ }
+
+ mfFontScale = 1.0;
+
+ mhDC = 0;
+ mhPen = 0;
+ mhBrush = 0;
+ mhRegion = 0;
+ mhDefPen = 0;
+ mhDefBrush = 0;
+ mhDefFont = 0;
+ mhDefPal = 0;
+ mpStdClipRgnData = NULL;
+ mpLogFont = NULL;
+ mpFontCharSets = NULL;
+ mpFontAttrCache = NULL;
+ mnFontCharSetCount = 0;
+ mpFontKernPairs = NULL;
+ mnFontKernPairCount = 0;
+ mbFontKernInit = FALSE;
+ mbXORMode = FALSE;
+ mnPenWidth = GSL_PEN_WIDTH;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalGraphics::~WinSalGraphics()
+{
+ // free obsolete GDI objekts
+ ReleaseFonts();
+
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ // Cache-Daten zerstoeren
+ if ( mpStdClipRgnData )
+ delete [] mpStdClipRgnData;
+
+ if ( mpLogFont )
+ delete mpLogFont;
+
+ if ( mpFontCharSets )
+ delete mpFontCharSets;
+
+ if ( mpFontKernPairs )
+ delete mpFontKernPairs;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetResolution( long& rDPIX, long& rDPIY )
+{
+ rDPIX = GetDeviceCaps( mhDC, LOGPIXELSX );
+ rDPIY = GetDeviceCaps( mhDC, 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;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt16 WinSalGraphics::GetBitCount()
+{
+ return (sal_uInt16)GetDeviceCaps( mhDC, BITSPIXEL );
+}
+
+// -----------------------------------------------------------------------
+
+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;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::ResetClipRegion()
+{
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ SelectClipRgn( mhDC, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::setClipRegion( const Region& i_rClip )
+{
+ if ( mhRegion )
+ {
+ DeleteRegion( mhRegion );
+ mhRegion = 0;
+ }
+
+ if( i_rClip.HasPolyPolygon() )
+ {
+ // TODO: ConvertToB2DPolyPolygon actually is kind of const, just it does not advertise it in the header
+ basegfx::B2DPolyPolygon aPolyPolygon( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() );
+ const sal_uInt32 nCount(aPolyPolygon.count());
+
+ if( nCount )
+ {
+ std::vector< POINT > aPolyPoints;
+ aPolyPoints.reserve( 1024 );
+ std::vector< INT > aPolyCounts( nCount, 0 );
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ basegfx::B2DPolygon aPoly( aPolyPolygon.getB2DPolygon(a) );
+ aPoly = basegfx::tools::adaptiveSubdivideByDistance( aPoly, 1 );
+ const sal_uInt32 nPoints = aPoly.count();
+ aPolyCounts[a] = nPoints;
+ for( sal_uInt32 b = 0; b < nPoints; b++ )
+ {
+ basegfx::B2DPoint aPt( aPoly.getB2DPoint( b ) );
+ POINT aPOINT;
+ aPOINT.x = (LONG)aPt.getX();
+ aPOINT.y = (LONG)aPt.getY();
+ aPolyPoints.push_back( aPOINT );
+ }
+ }
+ mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE );
+ }
+ }
+ else
+ {
+ ULONG nRectCount = i_rClip.GetRectCount();
+
+ ULONG nRectBufSize = sizeof(RECT)*nRectCount;
+ if ( nRectCount < 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 = nRectCount;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ SetRectEmpty( pBoundRect );
+ RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ bool bFirstClipRect = true;
+
+ ImplRegionInfo aInfo;
+ long nX, nY, nW, nH;
+ bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
+ while( bRegionRect )
+ {
+ if ( nW && nH )
+ {
+ long nRight = nX + nW;
+ long nBottom = nY + nH;
+
+ if ( bFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ bFirstClipRect = false;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pNextClipRect->left = (int)nX;
+ pNextClipRect->top = (int)nY;
+ pNextClipRect->right = (int)nRight;
+ pNextClipRect->bottom = (int)nBottom;
+ pNextClipRect++;
+ }
+ else
+ {
+ mpClipRgnData->rdh.nCount--;
+ mpClipRgnData->rdh.nRgnSize -= sizeof( RECT );
+ }
+ bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
+ }
+ // create clip region from ClipRgnData
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ mhRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else if( mpClipRgnData->rdh.nCount > 1 )
+ {
+ 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( 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( mhDC, mhRegion );
+ return mhRegion != 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetLineColor()
+{
+ // create and select new pen
+ HPEN hNewPen = GetStockPen( NULL_PEN );
+ HPEN hOldPen = SelectPen( mhDC, hNewPen );
+
+ // destory or save old pen
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ else
+ mhDefPen = hOldPen;
+
+ // set new data
+ mhPen = hNewPen;
+ mbPen = FALSE;
+ mbStockPen = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetLineColor( SalColor nSalColor )
+{
+ maLineColor = nSalColor;
+ COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+ HPEN hNewPen = 0;
+ sal_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( mhDC, hNewPen );
+
+ // destory or save old pen
+ if ( mhPen )
+ {
+ if ( !mbStockPen )
+ DeletePen( mhPen );
+ }
+ else
+ mhDefPen = hOldPen;
+
+ // set new data
+ mnPenColor = nPenColor;
+ mhPen = hNewPen;
+ mbPen = TRUE;
+ mbStockPen = bStockPen;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetFillColor()
+{
+ // create and select new brush
+ HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hNewBrush );
+
+ // destory or save old brush
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+ else
+ mhDefBrush = hOldBrush;
+
+ // set new data
+ mhBrush = hNewBrush;
+ mbBrush = FALSE;
+ mbStockBrush = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+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;
+ sal_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( mhDC, hNewBrush );
+
+ // destory or save old brush
+ if ( mhBrush )
+ {
+ if ( !mbStockBrush )
+ DeleteBrush( mhBrush );
+ }
+ else
+ mhDefBrush = hOldBrush;
+
+ // set new data
+ mnBrushColor = nBrushColor;
+ mhBrush = hNewBrush;
+ mbBrush = TRUE;
+ mbStockBrush = bStockBrush;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetXORMode( bool bSet, bool )
+{
+ mbXORMode = bSet;
+ ::SetROP2( mhDC, bSet ? R2_XORPEN : R2_COPYPEN );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor )
+{
+ SetLineColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor )
+{
+ SetFillColor( ImplGetROPSalColor( nROPColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPixel( long nX, long nY )
+{
+ if ( mbXORMode )
+ {
+ HBRUSH hBrush = CreateSolidBrush( mnPenColor );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ SetPixel( mhDC, (int)nX, (int)nY, mnPenColor );
+}
+
+// -----------------------------------------------------------------------
+
+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( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX, (int)nY, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ ::SetPixel( mhDC, (int)nX, (int)nY, nCol );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
+{
+ MoveToEx( mhDC, (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( mhDC, (int)nX2, (int)nY2 );
+
+ if ( bPaintEnd && !mbPrinter )
+ {
+ if ( mbXORMode )
+ {
+ HBRUSH hBrush = CreateSolidBrush( mnPenColor );
+ HBRUSH hOldBrush = SelectBrush( mhDC, hBrush );
+ PatBlt( mhDC, (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT );
+ SelectBrush( mhDC, hOldBrush );
+ DeleteBrush( hBrush );
+ }
+ else
+ SetPixel( mhDC, (int)nX2, (int)nY2, mnPenColor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
+{
+ if ( !mbPen )
+ {
+ if ( !mbPrinter )
+ {
+ PatBlt( mhDC, (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( mhDC, &aWinRect, mhBrush );
+ }
+ }
+ else
+ WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry )
+{
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
+
+ POINT* pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry )
+{
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolygon(): POINT != SalPoint" );
+
+ POINT* pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+}
+
+// -----------------------------------------------------------------------
+
+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];
+ // Unter NT koennen wir das Array direkt weiterreichen
+ 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( mhDC, 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( mhDC, pWinPointAryAry, *pWinPointAry );
+ else
+ WIN_PolyPolygon( mhDC, pWinPointAryAry, (int*)pWinPointAry, nPoly );
+ }
+
+ if ( pWinPointAry != aWinPointAry )
+ delete [] pWinPointAry;
+ if ( pWinPointAryAry != aWinPointAryAry )
+ delete [] pWinPointAryAry;
+}
+
+// -----------------------------------------------------------------------
+
+#define SAL_POLY_STACKBUF 32
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" );
+
+ ImplRenderPath( mhDC, nPoints, pPtAry, pFlgAry );
+
+ return sal_True;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ 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;
+ }
+
+ ImplPreparePolyDraw(true, 1, &nPoints, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry);
+
+ sal_Bool bRet( sal_False );
+
+ if( BeginPath( mhDC ) )
+ {
+ PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nPoints);
+
+ if( EndPath( mhDC ) )
+ {
+ if( StrokeAndFillPath( mhDC ) )
+ bRet = sal_True;
+ }
+ }
+
+ if( pWinPointAry != aStackAry1 )
+ {
+ delete [] pWinPointAry;
+ delete [] pWinFlagAry;
+ }
+
+ return bRet;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints,
+ const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
+{
+#ifdef USE_GDI_BEZIERS
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" );
+
+ sal_uLong nCurrPoly, nTotalPoints;
+ const sal_uLong* pCurrPoints = pPoints;
+ for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly )
+ nTotalPoints += *pCurrPoints++;
+
+ POINT aStackAry1[SAL_POLY_STACKBUF];
+ BYTE aStackAry2[SAL_POLY_STACKBUF];
+ POINT* pWinPointAry;
+ BYTE* pWinFlagAry;
+ if( nTotalPoints > SAL_POLY_STACKBUF )
+ {
+ pWinPointAry = new POINT[ nTotalPoints ];
+ pWinFlagAry = new BYTE[ nTotalPoints ];
+ }
+ else
+ {
+ pWinPointAry = aStackAry1;
+ pWinFlagAry = aStackAry2;
+ }
+
+ ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry);
+
+ sal_Bool bRet( sal_False );
+
+ if( BeginPath( mhDC ) )
+ {
+ PolyDraw(mhDC, pWinPointAry, pWinFlagAry, nTotalPoints);
+
+ if( EndPath( mhDC ) )
+ {
+ if( StrokeAndFillPath( mhDC ) )
+ bRet = sal_True;
+ }
+ }
+
+ if( pWinPointAry != aStackAry1 )
+ {
+ delete [] pWinPointAry;
+ delete [] pWinFlagAry;
+ }
+
+ return bRet;
+#else
+ return sal_False;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF
+#define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
+ // in the first 4096 bytes
+
+static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* 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 NULL;
+}
+
+static sal_Bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize )
+{
+ sal_Bool bRetValue = FALSE;
+ BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%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;
+ sal_Bool bDivision = FALSE;
+ sal_Bool bNegative = FALSE;
+ sal_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;
+}
+
+sal_Bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize )
+{
+ sal_Bool bRetValue = FALSE;
+
+ if ( mbPrinter )
+ {
+ int nEscape = POSTSCRIPT_PASSTHROUGH;
+
+ if ( Escape( mhDC, QUERYESCSUPPORT, sizeof( int ), ( LPSTR )&nEscape, 0 ) )
+ {
+ double nBoundingBox[4];
+
+ if ( ImplGetBoundingBox( nBoundingBox, (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 != 0 &&
+ mpStdClipRgnData != NULL &&
+ mpClipRgnData == mpStdClipRgnData &&
+ mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+
+ aBuf.append( "\nnewpath\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " moveto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->top );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->right );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n" );
+ aBuf.append( pRect->left );
+ aBuf.append( " " );
+ aBuf.append( pRect->bottom );
+ aBuf.append( " lineto\n"
+ "closepath\n"
+ "clip\n"
+ "newpath\n" );
+ }
+
+ // #107797# Write out buffer
+ // ----------------------------------------------------------------------------------
+ *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+
+
+ // #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[" );
+ aBuf.append( dM11 );
+ aBuf.append( " 0 0 " );
+ aBuf.append( dM22 );
+ aBuf.append( ' ' );
+ aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
+ aBuf.append( ' ' );
+ aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
+ aBuf.append( "] concat\n"
+ "%%BeginDocument:\n" );
+ *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+
+
+ // #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
+ *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)nDoNow;
+ memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow );
+ sal_uLong nResult = Escape ( mhDC, nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 );
+ 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" );
+ *((sal_uInt16*)aBuf.getStr()) = (sal_uInt16)( aBuf.getLength() - 2 );
+ Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
+ bRetValue = TRUE;
+ }
+ }
+ }
+
+ return bRetValue;
+}
+
+// -----------------------------------------------------------------------
+
+SystemGraphicsData WinSalGraphics::GetGraphicsData() const
+{
+ SystemGraphicsData aRes;
+ aRes.nSize = sizeof(aRes);
+ aRes.hDC = mhDC;
+ return aRes;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/win/source/gdi/salgdi2.cxx b/vcl/win/source/gdi/salgdi2.cxx
new file mode 100644
index 000000000000..5ac117a596d9
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi2.cxx
@@ -0,0 +1,824 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <tools/svwin.h>
+#include <tools/debug.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/salbmp.h>
+#include <win/saldata.hxx>
+#include <win/salids.hrc>
+#include <win/salgdi.h>
+#include <win/salframe.h>
+
+bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const
+{
+ static bool bAllowForTest(true);
+ bool bRet = false;
+
+ switch( eType )
+ {
+ case OutDevSupport_TransparentRect:
+ bRet = mbVirDev || mbWindow;
+ break;
+ case OutDevSupport_B2DClip:
+ bRet = true;
+ break;
+ case OutDevSupport_B2DDraw:
+ bRet = bAllowForTest;
+ default: break;
+ }
+ return bRet;
+}
+
+// =======================================================================
+
+void WinSalGraphics::copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics )
+{
+ HDC hSrcDC;
+ DWORD nRop;
+
+ if ( pSrcGraphics )
+ hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->mhDC;
+ else
+ hSrcDC = mhDC;
+
+ if ( mbXORMode )
+ nRop = SRCINVERT;
+ else
+ nRop = SRCCOPY;
+
+ if ( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) &&
+ (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
+ {
+ BitBlt( mhDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hSrcDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ nRop );
+ }
+ else
+ {
+ int nOldStretchMode = SetStretchBltMode( mhDC, STRETCH_DELETESCANS );
+ StretchBlt( mhDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hSrcDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
+ nRop );
+ SetStretchBltMode( mhDC, nOldStretchMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplCalcOutSideRgn( const RECT& rSrcRect,
+ int nLeft, int nTop, int nRight, int nBottom,
+ HRGN& rhInvalidateRgn )
+{
+ HRGN hTempRgn;
+
+ // Bereiche ausserhalb des sichtbaren Bereiches berechnen
+ 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 WinSalGraphics::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;
+
+ // Muessen die ueberlappenden Bereiche auch invalidiert werden?
+ 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;
+ int nRgnType;
+
+ // 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 );
+
+ // Bereiche die von anderen Fenstern ueberlagert werden berechnen
+ 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 );
+ 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
+ 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( mhDC, hOldClipRgn );
+
+ bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate
+ ExtSelectClipRgn( mhDC, hInvalidateRgn, RGN_DIFF );
+ }
+ }
+ }
+ }
+
+ BitBlt( mhDC,
+ (int)nDestX, (int)nDestY,
+ (int)nSrcWidth, (int)nSrcHeight,
+ mhDC,
+ (int)nSrcX, (int)nSrcY,
+ SRCCOPY );
+
+ if( bRestoreClipRgn )
+ {
+ // restore old clip region
+ if( nOldClipRgnType != ERROR )
+ SelectClipRgn( mhDC, hOldClipRgn);
+ DeleteRegion( hOldClipRgn );
+
+ // invalidate regions that were not copied
+ bool bInvalidate = true;
+
+ // Combine Invalidate Region with existing ClipRegion
+ HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 );
+ if ( GetClipRgn( mhDC, 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 );
+ // Hier loesen wir nur ein Update aus, wenn es der
+ // MainThread ist, damit es beim Bearbeiten der
+ // Paint-Message keinen Deadlock gibt, da der
+ // SolarMutex durch diesen Thread schon gelockt ist
+ SalData* pSalData = GetSalData();
+ DWORD nCurThreadId = GetCurrentThreadId();
+ if ( pSalData->mnAppThreadId == nCurThreadId )
+ UpdateWindow( mhWnd );
+ }
+
+ DeleteRegion( hInvalidateRgn );
+ }
+
+}
+
+// -----------------------------------------------------------------------
+
+void ImplDrawBitmap( HDC hDC,
+ const SalTwoRect* pPosAry, const WinSalBitmap& rSalBitmap,
+ sal_Bool bPrinter, int nDrawMode )
+{
+ if( hDC )
+ {
+ HGLOBAL hDrawDIB;
+ HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB();
+ WinSalBitmap* pTmpSalBmp = NULL;
+ sal_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)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ (int)pPosAry->mnSrcX, (int)(pBIH->biHeight - pPosAry->mnSrcHeight - pPosAry->mnSrcY),
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->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);
+ sal_Bool bMono = ( rSalBitmap.GetBitCount() == 1 );
+
+ if( bMono )
+ {
+ nOldBkColor = SetBkColor( hDC, RGB( 0xFF, 0xFF, 0xFF ) );
+ nOldTextColor = ::SetTextColor( hDC, RGB( 0x00, 0x00, 0x00 ) );
+ }
+
+ if ( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) &&
+ (pPosAry->mnSrcHeight == pPosAry->mnDestHeight) )
+ {
+ BitBlt( hDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hBmpDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ nDrawMode );
+ }
+ else
+ {
+ const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
+
+ StretchBlt( hDC,
+ (int)pPosAry->mnDestX, (int)pPosAry->mnDestY,
+ (int)pPosAry->mnDestWidth, (int)pPosAry->mnDestHeight,
+ hBmpDC,
+ (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY,
+ (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight,
+ nDrawMode );
+
+ SetStretchBltMode( hDC, nOldStretchMode );
+ }
+
+ if( bMono )
+ {
+ SetBkColor( hDC, nOldBkColor );
+ ::SetTextColor( hDC, nOldTextColor );
+ }
+
+ ImplReleaseCachedDC( CACHED_HDC_DRAW );
+ }
+
+ if( bPrintDDB )
+ delete pTmpSalBmp;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap )
+{
+ ImplDrawBitmap( mhDC, pPosAry, static_cast<const WinSalBitmap&>(rSalBitmap),
+ mbPrinter,
+ mbXORMode ? SRCINVERT : SRCCOPY );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ SalColor nTransparentColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(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( pPosAry, rSalBitmap, *pMask );
+
+ delete pMask;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ const SalBitmap& rSTransparentBitmap )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+ const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap);
+
+ SalTwoRect aPosAry = *pPosAry;
+ int nDstX = (int)aPosAry.mnDestX;
+ int nDstY = (int)aPosAry.mnDestY;
+ int nDstWidth = (int)aPosAry.mnDestWidth;
+ int nDstHeight = (int)aPosAry.mnDestHeight;
+ HDC hDC = mhDC;
+ 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 );
+
+ // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
+ // die Farben der Maske richtig auf die Palette abzubilden,
+ // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
+ 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 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
+ const SalBitmap& rSrcBitmap,
+ const SalBitmap& rAlphaBmp )
+{
+ (void)rTR; (void)rSrcBitmap; (void)rAlphaBmp;
+
+ // TODO(P3): implement alpha bmp blits. Catch: Windows only
+ // handles 32bpp, premultiplied bitmaps
+ return false;
+}
+
+// -----------------------------------------------------------------------
+
+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,
+ 255 - 255L*nTransparency/100,
+ 0
+ };
+
+ // hMemDC contains a 1x1 bitmap of the right color - stretch-blit
+ // that to dest hdc
+ bool bRet = AlphaBlend( mhDC, nX, nY, nWidth, nHeight,
+ hMemDC, 0,0,1,1,
+ aFunc ) == TRUE;
+
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSSalBitmap,
+ SalColor nMaskColor )
+{
+ DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
+
+ const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
+
+ SalTwoRect aPosAry = *pPosAry;
+ const BYTE cRed = SALCOLOR_RED( nMaskColor );
+ const BYTE cGreen = SALCOLOR_GREEN( nMaskColor );
+ const BYTE cBlue = SALCOLOR_BLUE( nMaskColor );
+ HDC hDC = mhDC;
+ HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) );
+ HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush );
+
+ // bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
+ // die Farben der Maske richtig auf die Palette abzubilden,
+ // wenn wir die DIB direkt ausgeben => DDB-Ausgabe
+ 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 );
+}
+
+// -----------------------------------------------------------------------
+
+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 = mhDC;
+ HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
+ HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
+ sal_Bool bRet;
+ DWORD err = 0;
+
+ 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
+ {
+ err = GetLastError();
+ // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers)
+ DeleteBitmap( hBmpBitmap );
+ }
+
+ return pSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+SalColor WinSalGraphics::getPixel( long nX, long nY )
+{
+ COLORREF aWinCol = ::GetPixel( mhDC, (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 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( mhDC, hDotPen );
+ HBRUSH hOldBrush = SelectBrush( mhDC, GetStockBrush( NULL_BRUSH ) );
+ int nOldROP = SetROP2( mhDC, R2_NOT );
+
+ WIN_Rectangle( mhDC, (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
+
+ SetROP2( mhDC, nOldROP );
+ SelectPen( mhDC, hOldPen );
+ SelectBrush( mhDC, 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( mhDC, 0 );
+ HBRUSH hOldBrush = SelectBrush( mhDC, pSalData->mh50Brush );
+ PatBlt( mhDC, nX, nY, nWidth, nHeight, PATINVERT );
+ ::SetTextColor( mhDC, nOldTextColor );
+ SelectBrush( mhDC, hOldBrush );
+ }
+ else
+ {
+ RECT aRect;
+ aRect.left = (int)nX;
+ aRect.top = (int)nY;
+ aRect.right = (int)nX+nWidth;
+ aRect.bottom = (int)nY+nHeight;
+ ::InvertRect( mhDC, &aRect );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
+{
+ HPEN hPen;
+ HPEN hOldPen;
+ HBRUSH hBrush;
+ HBRUSH hOldBrush = 0;
+ COLORREF nOldTextColor RGB(0,0,0);
+ int nOldROP = SetROP2( mhDC, 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( mhDC, 0 );
+ hOldBrush = SelectBrush( mhDC, hBrush );
+ }
+ hOldPen = SelectPen( mhDC, hPen );
+
+ POINT* pWinPtAry;
+ // Unter NT koennen wir das Array direkt weiterreichen
+ DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
+ "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
+
+ pWinPtAry = (POINT*)pPtAry;
+ // Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
+ // von Punkten
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ {
+ if ( !Polyline( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ Polyline( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+ }
+ else
+ {
+ if ( !WIN_Polygon( mhDC, pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
+ WIN_Polygon( mhDC, pWinPtAry, MAX_64KSALPOINTS );
+ }
+
+ SetROP2( mhDC, nOldROP );
+ SelectPen( mhDC, hOldPen );
+
+ if ( nSalFlags & SAL_INVERT_TRACKFRAME )
+ DeletePen( hPen );
+ else
+ {
+ ::SetTextColor( mhDC, nOldTextColor );
+ SelectBrush( mhDC, hOldBrush );
+ }
+}
diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx
new file mode 100755
index 000000000000..86f6ad0f4af1
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi3.cxx
@@ -0,0 +1,3079 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+#include <malloc.h>
+
+#include "rtl/logfile.hxx"
+#include "rtl/tencinfo.h"
+#include "rtl/textcvt.h"
+#include "rtl/bootstrap.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+#include "osl/module.h"
+#include "osl/file.hxx"
+#include "osl/thread.hxx"
+#include "osl/process.h"
+
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include "basegfx/matrix/b2dhommatrixtools.hxx"
+
+#include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
+
+#include "vcl/font.hxx"
+#include "vcl/svapp.hxx"
+
+#include "tools/poly.hxx"
+#include "tools/debug.hxx"
+#include "tools/stream.hxx"
+
+#include <tools/prewin.h>
+#include <windows.h>
+#include <tools/postwin.h>
+
+#include <vcl/sysdata.hxx>
+
+#include "win/wincomp.hxx"
+#include "win/saldata.hxx"
+#include "win/salgdi.h"
+
+#include "outfont.hxx"
+#include "fontsubset.hxx"
+#include "sallayout.hxx"
+#include "outdev.h" // for ImplGlyphFallbackFontSubstitution
+#include "sft.hxx"
+
+#ifdef GCP_KERN_HACK
+#include <algorithm>
+#endif
+
+#ifdef ENABLE_GRAPHITE
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#endif
+
+#include <vector>
+#include <set>
+#include <map>
+
+using namespace vcl;
+
+static const int MAXFONTHEIGHT = 2048;
+
+// -----------
+// - Inlines -
+// -----------
+
+inline FIXED FixedFromDouble( double d )
+{
+ const long l = (long) ( d * 65536. );
+ return *(FIXED*) &l;
+}
+
+// -----------------------------------------------------------------------
+
+inline int IntTimes256FromFixed(FIXED f)
+{
+ int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
+ return nFixedTimes256;
+}
+
+// =======================================================================
+
+// these variables can be static because they store system wide settings
+static bool bImplSalCourierScalable = false;
+static bool bImplSalCourierNew = false;
+
+
+// =======================================================================
+
+// -----------------------------------------------------------------------
+
+// TODO: also support temporary TTC font files
+typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
+
+class ImplFontAttrCache
+{
+private:
+ FontAttrMap aFontAttributes;
+ rtl::OUString aCacheFileName;
+ String aBaseURL;
+ sal_Bool bModified;
+
+protected:
+ String OptimizeURL( const String& rURL ) const;
+
+ enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
+
+public:
+ ImplFontAttrCache( const String& rCacheFileName, const String& rBaseURL );
+ ~ImplFontAttrCache();
+
+ ImplDevFontAttributes GetFontAttr( const String& rFontFileName ) const;
+ void AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& );
+};
+
+ImplFontAttrCache::ImplFontAttrCache( const String& rFileNameURL, const String& rBaseURL ) : aBaseURL( rBaseURL )
+{
+ bModified = FALSE;
+ aBaseURL.ToLowerAscii(); // Windows only, no problem...
+
+ // open the cache file
+ osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
+ SvFileStream aCacheFile( aCacheFileName, STREAM_READ );
+ if( !aCacheFile.IsOpen() )
+ return;
+
+ // check the cache version
+ sal_uInt32 nCacheMagic;
+ aCacheFile >> nCacheMagic;
+ if( nCacheMagic != ImplFontAttrCache::MAGIC )
+ return; // ignore cache and rewrite if no match
+
+ // read the cache entries from the file
+ String aFontFileURL, aFontName;
+ ImplDevFontAttributes aDFA;
+ for(;;)
+ {
+ aCacheFile.ReadByteString( aFontFileURL, RTL_TEXTENCODING_UTF8 );
+ if( !aFontFileURL.Len() )
+ break;
+ aCacheFile.ReadByteString( aDFA.maName, RTL_TEXTENCODING_UTF8 );
+
+ short n;
+ aCacheFile >> n; aDFA.meWeight = static_cast<FontWeight>(n);
+ aCacheFile >> n; aDFA.meItalic = static_cast<FontItalic>(n);
+ aCacheFile >> n; aDFA.mePitch = static_cast<FontPitch>(n);
+ aCacheFile >> n; aDFA.meWidthType = static_cast<FontWidth>(n);
+ aCacheFile >> n; aDFA.meFamily = static_cast<FontFamily>(n);
+ aCacheFile >> n; aDFA.mbSymbolFlag = (n != 0);
+
+ aCacheFile.ReadByteStringLine( aDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+
+ aFontAttributes[ aFontFileURL ] = aDFA;
+ }
+}
+
+ImplFontAttrCache::~ImplFontAttrCache()
+{
+ if ( bModified )
+ {
+ SvFileStream aCacheFile( aCacheFileName, STREAM_WRITE|STREAM_TRUNC );
+ if ( aCacheFile.IsWritable() )
+ {
+ sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
+ aCacheFile << nCacheMagic;
+
+ // write the cache entries to the file
+ FontAttrMap::const_iterator aIter = aFontAttributes.begin();
+ while ( aIter != aFontAttributes.end() )
+ {
+ const String rFontFileURL( (*aIter).first );
+ const ImplDevFontAttributes& rDFA( (*aIter).second );
+ aCacheFile.WriteByteString( rFontFileURL, RTL_TEXTENCODING_UTF8 );
+ aCacheFile.WriteByteString( rDFA.maName, RTL_TEXTENCODING_UTF8 );
+
+ aCacheFile << static_cast<short>(rDFA.meWeight);
+ aCacheFile << static_cast<short>(rDFA.meItalic);
+ aCacheFile << static_cast<short>(rDFA.mePitch);
+ aCacheFile << static_cast<short>(rDFA.meWidthType);
+ aCacheFile << static_cast<short>(rDFA.meFamily);
+ aCacheFile << static_cast<short>(rDFA.mbSymbolFlag != false);
+
+ aCacheFile.WriteByteStringLine( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
+
+ aIter++;
+ }
+ // EOF Marker
+ String aEmptyStr;
+ aCacheFile.WriteByteString( aEmptyStr, RTL_TEXTENCODING_UTF8 );
+ }
+ }
+}
+
+String ImplFontAttrCache::OptimizeURL( const String& rURL ) const
+{
+ String aOptimizedFontFileURL( rURL );
+ aOptimizedFontFileURL.ToLowerAscii(); // Windows only, no problem...
+ if ( aOptimizedFontFileURL.CompareTo( aBaseURL, aBaseURL.Len() ) == COMPARE_EQUAL )
+ aOptimizedFontFileURL = aOptimizedFontFileURL.Copy( aBaseURL.Len() );
+ return aOptimizedFontFileURL;
+}
+
+ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const String& rFontFileName ) const
+{
+ ImplDevFontAttributes aDFA;
+ FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
+ if( it != aFontAttributes.end() )
+ {
+ aDFA = it->second;
+ }
+ return aDFA;
+}
+
+void ImplFontAttrCache::AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& rDFA )
+{
+ DBG_ASSERT( rFontFileName.Len() && rDFA.maName.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
+ if ( rFontFileName.Len() && rDFA.maName.Len() )
+ {
+ aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
+ bModified = TRUE;
+ }
+}
+
+// =======================================================================
+
+// raw font data with a scoped lifetime
+class RawFontData
+{
+public:
+ explicit RawFontData( HDC, DWORD nTableTag=0 );
+ ~RawFontData() { delete[] mpRawBytes; }
+ const unsigned char* get() const { return mpRawBytes; }
+ const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
+ const int size() const { return mnByteCount; }
+
+private:
+ unsigned char* mpRawBytes;
+ int mnByteCount;
+};
+
+RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
+: mpRawBytes( NULL )
+, mnByteCount( 0 )
+{
+ // get required size in bytes
+ mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
+ if( mnByteCount == GDI_ERROR )
+ return;
+ else if( !mnByteCount )
+ return;
+
+ // allocate the array
+ mpRawBytes = new unsigned char[ mnByteCount ];
+
+ // get raw data in chunks small enough for GetFontData()
+ int nRawDataOfs = 0;
+ DWORD nMaxChunkSize = 0x100000;
+ for(;;)
+ {
+ // calculate remaining raw data to get
+ DWORD nFDGet = mnByteCount - nRawDataOfs;
+ if( nFDGet <= 0 )
+ break;
+ // #i56745# limit GetFontData requests
+ if( nFDGet > nMaxChunkSize )
+ nFDGet = nMaxChunkSize;
+ const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
+ (void*)(mpRawBytes + nRawDataOfs), nFDGet );
+ if( !nFDGot )
+ break;
+ else if( nFDGot != GDI_ERROR )
+ nRawDataOfs += nFDGot;
+ else
+ {
+ // was the chunk too big? reduce it
+ nMaxChunkSize /= 2;
+ if( nMaxChunkSize < 0x10000 )
+ break;
+ }
+ }
+
+ // cleanup if the raw data is incomplete
+ if( nRawDataOfs != mnByteCount )
+ {
+ delete[] mpRawBytes;
+ mpRawBytes = NULL;
+ }
+}
+
+// ===========================================================================
+// platform specific font substitution hooks for glyph fallback enhancement
+// TODO: move into i18n module (maybe merge with svx/ucsubset.*
+// or merge with i18nutil/source/utility/unicode_data.h)
+struct Unicode2LangType
+{
+ sal_UCS4 mnMinCode;
+ sal_UCS4 mnMaxCode;
+ LanguageType mnLangID;
+};
+
+// entries marked with default-CJK get replaced with the default-CJK language
+#define LANGUAGE_DEFAULT_CJK 0xFFF0
+
+// map unicode ranges to languages supported by OOo
+// NOTE: due to the binary search used this list must be sorted by mnMinCode
+static Unicode2LangType aLangFromCodeChart[]= {
+ {0x0000, 0x007F, LANGUAGE_ENGLISH}, // Basic Latin
+ {0x0080, 0x024F, LANGUAGE_ENGLISH}, // Latin Extended-A and Latin Extended-B
+ {0x0250, 0x02AF, LANGUAGE_SYSTEM}, // IPA Extensions
+ {0x0370, 0x03FF, LANGUAGE_GREEK}, // Greek
+ {0x0590, 0x05FF, LANGUAGE_HEBREW}, // Hebrew
+ {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
+ {0x0900, 0x097F, LANGUAGE_HINDI}, // Devanagari
+ {0x0980, 0x09FF, LANGUAGE_BENGALI}, // Bengali
+ {0x0A80, 0x0AFF, LANGUAGE_GUJARATI}, // Gujarati
+ {0x0B00, 0x0B7F, LANGUAGE_ORIYA}, // Oriya
+ {0x0B80, 0x0BFF, LANGUAGE_TAMIL}, // Tamil
+ {0x0C00, 0x0C7F, LANGUAGE_TELUGU}, // Telugu
+ {0x0C80, 0x0CFF, LANGUAGE_KANNADA}, // Kannada
+ {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM}, // Malayalam
+ {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
+ {0x0E00, 0x0E7F, LANGUAGE_THAI}, // Thai
+ {0x0E80, 0x0EFF, LANGUAGE_LAO}, // Lao
+ {0x0F00, 0x0FFF, LANGUAGE_TIBETAN}, // Tibetan
+ {0x1000, 0x109F, LANGUAGE_BURMESE}, // Burmese
+ {0x10A0, 0x10FF, LANGUAGE_GEORGIAN}, // Georgian
+ {0x1100, 0x11FF, LANGUAGE_KOREAN}, // Hangul Jamo, Korean-specific
+// {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
+// {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
+ {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
+// {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
+// {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
+// {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
+// {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
+// {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
+// {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
+// {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
+ {0x1780, 0x17FF, LANGUAGE_KHMER}, // Khmer
+ {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN}, // Mongolian
+// {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
+// {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
+// {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
+ {0x19E0, 0x19FF, LANGUAGE_KHMER}, // Khmer Symbols
+// {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
+// {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
+// {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
+ {0x1E00, 0x1EFF, LANGUAGE_ENGLISH}, // Latin Extended Additional
+ {0x1F00, 0x1FFF, LANGUAGE_GREEK}, // Greek Extended
+ {0x2C60, 0x2C7F, LANGUAGE_ENGLISH}, // Latin Extended-C
+ {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
+ {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK}, // CJK Symbols and punctuation
+ {0x3040, 0x30FF, LANGUAGE_JAPANESE}, // Japanese Hiragana + Katakana
+ {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
+ {0x3130, 0x318F, LANGUAGE_KOREAN}, // Hangul Compatibility Jamo, Kocrean-specific
+ {0x3190, 0x319F, LANGUAGE_JAPANESE}, // Kanbun
+ {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
+ {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK}, // CJK Ideographs
+ {0x31F0, 0x31FF, LANGUAGE_JAPANESE}, // Japanese Katakana Phonetic Extensions
+ {0x3200, 0x321F, LANGUAGE_KOREAN}, // Parenthesized Hangul
+ {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK}, // Parenthesized Ideographs
+ {0x3260, 0x327F, LANGUAGE_KOREAN}, // Circled Hangul
+ {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK}, // Circled Ideographs
+ {0x32d0, 0x32FF, LANGUAGE_JAPANESE}, // Japanese Circled Katakana
+ {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension A
+ {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK}, // Unified CJK Ideographs
+ {0xA720, 0xA7FF, LANGUAGE_ENGLISH}, // Latin Extended-D
+ {0xAC00, 0xD7AF, LANGUAGE_KOREAN}, // Hangul Syllables, Korean-specific
+ {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK}, // CJK Compatibility Ideographs
+ {0xFB00, 0xFB4F, LANGUAGE_HEBREW}, // Hebrew Presentation Forms
+ {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
+ {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
+ {0xFF65, 0xFF9F, LANGUAGE_JAPANESE}, // Japanese Halfwidth Katakana variant
+ {0xFFA0, 0xFFDC, LANGUAGE_KOREAN}, // Kocrean halfwidth hangual variant
+ {0x10140, 0x1018F, LANGUAGE_GREEK}, // Ancient Greak numbers
+ {0x1D200, 0x1D24F, LANGUAGE_GREEK}, // Ancient Greek Musical
+ {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension B
+ {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK} // CJK Compatibility Ideographs Supplement
+};
+
+// get language matching to the missing char
+LanguageType MapCharToLanguage( sal_UCS4 uChar )
+{
+ // entries marked with default-CJK get replaced with the prefered CJK language
+ static bool bFirst = true;
+ if( bFirst )
+ {
+ bFirst = false;
+
+ // use method suggested in #i97086# to determnine the systems default language
+ // TODO: move into i18npool or sal/osl/w32/nlsupport.c
+ LanguageType nDefaultLang = 0;
+ HKEY hKey = NULL;
+ LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
+ 0, KEY_QUERY_VALUE, &hKey );
+ char aKeyValBuf[16];
+ DWORD nKeyValSize = sizeof(aKeyValBuf);
+ if( ERROR_SUCCESS == lResult )
+ lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
+ aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
+ if( ERROR_SUCCESS == lResult )
+ nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
+
+ // TODO: use the default-CJK language selected in
+ // Tools->Options->LangSettings->Languages when it becomes available here
+ if( !nDefaultLang )
+ nDefaultLang = Application::GetSettings().GetUILanguage();
+
+ LanguageType nDefaultCJK = LANGUAGE_CHINESE;
+ switch( nDefaultLang )
+ {
+ case LANGUAGE_JAPANESE:
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ case LANGUAGE_CHINESE_SIMPLIFIED:
+ case LANGUAGE_CHINESE_TRADITIONAL:
+ case LANGUAGE_CHINESE_SINGAPORE:
+ case LANGUAGE_CHINESE_HONGKONG:
+ case LANGUAGE_CHINESE_MACAU:
+ nDefaultCJK = nDefaultLang;
+ break;
+ default:
+ nDefaultCJK = LANGUAGE_CHINESE;
+ break;
+ }
+
+ // change the marked entries to prefered language
+ static const int nCount = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart));
+ for( int i = 0; i < nCount; ++i )
+ {
+ if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
+ aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
+ }
+ }
+
+ // binary search
+ int nLow = 0;
+ int nHigh = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart)) - 1;
+ while( nLow <= nHigh )
+ {
+ int nMiddle = (nHigh + nLow) / 2;
+ if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
+ nHigh = nMiddle - 1;
+ else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
+ nLow = nMiddle + 1;
+ else
+ return aLangFromCodeChart[ nMiddle].mnLangID;
+ }
+
+ return LANGUAGE_DONTKNOW;
+}
+
+class WinGlyphFallbackSubstititution
+: public ImplGlyphFallbackFontSubstitution
+{
+public:
+ explicit WinGlyphFallbackSubstititution( HDC );
+
+ bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingChars ) const;
+private:
+ HDC mhDC;
+ bool HasMissingChars( const ImplFontData*, const rtl::OUString& rMissingChars ) const;
+};
+
+inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
+: mhDC( hDC )
+{}
+
+void ImplGetLogFontFromFontSelect( HDC, const ImplFontSelectData*,
+ LOGFONTW&, bool /*bTestVerticalAvail*/ );
+
+// does a font face hold the given missing characters?
+bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData* pFace, const rtl::OUString& rMissingChars ) const
+{
+ const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFace);
+ const ImplFontCharMap* pCharMap = pWinFont->GetImplFontCharMap();
+ if( !pCharMap )
+ {
+ // construct a Size structure as the parameter of constructor of class ImplFontSelectData
+ const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
+ // create a ImplFontSelectData object for getting s LOGFONT
+ const ImplFontSelectData aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
+ // construct log font
+ LOGFONTW aLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
+
+ // create HFONT from log font
+ HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
+ // select the new font into device
+ HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
+
+ // read CMAP table to update their pCharMap
+ pWinFont->UpdateFromHDC( mhDC );;
+
+ // cleanup temporary font
+ ::SelectFont( mhDC, hOldFont );
+ ::DeleteFont( hNewFont );
+
+ // get the new charmap
+ pCharMap = pWinFont->GetImplFontCharMap();
+ }
+
+ // avoid fonts with unknown CMAP subtables for glyph fallback
+ if( !pCharMap || pCharMap->IsDefaultMap() )
+ return false;
+ pCharMap->AddReference();
+
+ int nMatchCount = 0;
+ // static const int nMaxMatchCount = 1; // TODO: tolerate more missing characters?
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; ++nStrIdx )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ nMatchCount += pCharMap->HasChar( uChar );
+ break; // for now
+ }
+ pCharMap->DeReference();
+
+ const bool bHasMatches = (nMatchCount > 0);
+ return bHasMatches;
+}
+
+// find a fallback font for missing characters
+// TODO: should stylistic matches be searched and prefered?
+bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData, rtl::OUString& rMissingChars ) const
+{
+ // guess a locale matching to the missing chars
+ com::sun::star::lang::Locale aLocale;
+
+ sal_Int32 nStrIdx = 0;
+ const sal_Int32 nStrLen = rMissingChars.getLength();
+ while( nStrIdx < nStrLen )
+ {
+ const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
+ const LanguageType eLang = MapCharToLanguage( uChar );
+ if( eLang == LANGUAGE_DONTKNOW )
+ continue;
+ MsLangId::convertLanguageToLocale( eLang, aLocale );
+ break;
+ }
+
+ // fall back to default UI locale if the missing characters are inconclusive
+ if( nStrIdx >= nStrLen )
+ aLocale = Application::GetSettings().GetUILocale();
+
+ // first level fallback:
+ // try use the locale specific default fonts defined in VCL.xcu
+ const ImplDevFontList* pDevFontList = ImplGetSVData()->maGDIData.mpScreenFontList;
+ /*const*/ ImplDevFontListData* pDevFont = pDevFontList->ImplFindByLocale( aLocale );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // are the missing characters symbols?
+ pDevFont = pDevFontList->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL,
+ rFontSelData.meWeight, rFontSelData.meWidthType,
+ rFontSelData.meFamily, rFontSelData.meItalic, rFontSelData.maSearchName );
+ if( pDevFont )
+ {
+ const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
+ if( HasMissingChars( pFace, rMissingChars ) )
+ {
+ rFontSelData.maSearchName = pDevFont->GetSearchName();
+ return true;
+ }
+ }
+
+ // last level fallback, check each font type face one by one
+ const ImplGetDevFontList* pTestFontList = pDevFontList->GetDevFontList();
+ // limit the count of fonts to be checked to prevent hangs
+ static const int MAX_GFBFONT_COUNT = 600;
+ int nTestFontCount = pTestFontList->Count();
+ if( nTestFontCount > MAX_GFBFONT_COUNT )
+ nTestFontCount = MAX_GFBFONT_COUNT;
+
+ for( int i = 0; i < nTestFontCount; ++i )
+ {
+ const ImplFontData* pFace = pTestFontList->Get( i );
+ if( !HasMissingChars( pFace, rMissingChars ) )
+ continue;
+ rFontSelData.maSearchName = pFace->maName;
+ return true;
+ }
+
+ return false;
+}
+
+// =======================================================================
+
+struct ImplEnumInfo
+{
+ HDC mhDC;
+ ImplDevFontList* mpList;
+ String* mpName;
+ LOGFONTA* mpLogFontA;
+ LOGFONTW* mpLogFontW;
+ UINT mnPreferedCharSet;
+ bool mbCourier;
+ bool mbImplSalCourierScalable;
+ bool mbImplSalCourierNew;
+ bool mbPrinter;
+ int mnFontCount;
+};
+
+// =======================================================================
+
+static CharSet ImplCharSetToSal( BYTE nCharSet )
+{
+ rtl_TextEncoding eTextEncoding;
+
+ if ( nCharSet == OEM_CHARSET )
+ {
+ UINT nCP = (sal_uInt16)GetOEMCP();
+ switch ( nCP )
+ {
+ // It is unclear why these two (undefined?) code page numbers are
+ // handled specially here:
+ case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
+ case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
+ default:
+ eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
+ break;
+ };
+ }
+ else
+ {
+ if( nCharSet )
+ eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
+ else
+ eTextEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+
+ return eTextEncoding;
+}
+
+// -----------------------------------------------------------------------
+
+static FontFamily ImplFamilyToSal( BYTE nFamily )
+{
+ switch ( nFamily & 0xF0 )
+ {
+ case FF_DECORATIVE:
+ return FAMILY_DECORATIVE;
+
+ case FF_MODERN:
+ return FAMILY_MODERN;
+
+ case FF_ROMAN:
+ return FAMILY_ROMAN;
+
+ case FF_SCRIPT:
+ return FAMILY_SCRIPT;
+
+ case FF_SWISS:
+ return FAMILY_SWISS;
+
+ default:
+ break;
+ }
+
+ return FAMILY_DONTKNOW;
+}
+
+// -----------------------------------------------------------------------
+
+static BYTE ImplFamilyToWin( FontFamily eFamily )
+{
+ switch ( eFamily )
+ {
+ case FAMILY_DECORATIVE:
+ return FF_DECORATIVE;
+
+ case FAMILY_MODERN:
+ return FF_MODERN;
+
+ case FAMILY_ROMAN:
+ return FF_ROMAN;
+
+ case FAMILY_SCRIPT:
+ return FF_SCRIPT;
+
+ case FAMILY_SWISS:
+ return FF_SWISS;
+
+ case FAMILY_SYSTEM:
+ return FF_SWISS;
+
+ default:
+ break;
+ }
+
+ return FF_DONTCARE;
+}
+
+// -----------------------------------------------------------------------
+
+static FontWeight ImplWeightToSal( int nWeight )
+{
+ if ( nWeight <= FW_THIN )
+ return WEIGHT_THIN;
+ else if ( nWeight <= FW_ULTRALIGHT )
+ return WEIGHT_ULTRALIGHT;
+ else if ( nWeight <= FW_LIGHT )
+ return WEIGHT_LIGHT;
+ else if ( nWeight < FW_MEDIUM )
+ return WEIGHT_NORMAL;
+ else if ( nWeight == FW_MEDIUM )
+ return WEIGHT_MEDIUM;
+ else if ( nWeight <= FW_SEMIBOLD )
+ return WEIGHT_SEMIBOLD;
+ else if ( nWeight <= FW_BOLD )
+ return WEIGHT_BOLD;
+ else if ( nWeight <= FW_ULTRABOLD )
+ return WEIGHT_ULTRABOLD;
+ else
+ return WEIGHT_BLACK;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplWeightToWin( FontWeight eWeight )
+{
+ switch ( eWeight )
+ {
+ case WEIGHT_THIN:
+ return FW_THIN;
+
+ case WEIGHT_ULTRALIGHT:
+ return FW_ULTRALIGHT;
+
+ case WEIGHT_LIGHT:
+ return FW_LIGHT;
+
+ case WEIGHT_SEMILIGHT:
+ case WEIGHT_NORMAL:
+ return FW_NORMAL;
+
+ case WEIGHT_MEDIUM:
+ return FW_MEDIUM;
+
+ case WEIGHT_SEMIBOLD:
+ return FW_SEMIBOLD;
+
+ case WEIGHT_BOLD:
+ return FW_BOLD;
+
+ case WEIGHT_ULTRABOLD:
+ return FW_ULTRABOLD;
+
+ case WEIGHT_BLACK:
+ return FW_BLACK;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplLogPitchToSal( BYTE nPitch )
+{
+ if ( nPitch & FIXED_PITCH )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
+{
+ // Sausaecke bei MS !! siehe NT Hilfe
+ if ( !(nPitch & TMPF_FIXED_PITCH) )
+ return PITCH_FIXED;
+ else
+ return PITCH_VARIABLE;
+}
+
+// -----------------------------------------------------------------------
+
+inline BYTE ImplPitchToWin( FontPitch ePitch )
+{
+ if ( ePitch == PITCH_FIXED )
+ return FIXED_PITCH;
+ else if ( ePitch == PITCH_VARIABLE )
+ return VARIABLE_PITCH;
+ else
+ return DEFAULT_PITCH;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
+ const NEWTEXTMETRICA& rMetric, DWORD nFontType )
+{
+ ImplDevFontAttributes aDFA;
+
+ const LOGFONTA rLogFont = rEnumFont.elfLogFont;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
+ aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
+ aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
+
+ // get the font face name
+ aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
+
+ // use the face's style name only if it looks reasonable
+ const char* pStyleName = (const char*)rEnumFont.elfStyle;
+ const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
+ const char* p = pStyleName;
+ for(; *p && (p < pEnd); ++p )
+ if( (0x00 < *p) && (*p < 0x20) )
+ break;
+ if( p < pEnd )
+ aDFA.maStyleName = ImplSalGetUniString( pStyleName );
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
+ aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
+ aDFA.mnQuality += 10;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ // TODO: add alias names
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
+ const NEWTEXTMETRICW& rMetric, DWORD nFontType )
+{
+ ImplDevFontAttributes aDFA;
+
+ const LOGFONTW rLogFont = rEnumFont.elfLogFont;
+
+ // get font face attributes
+ aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
+ aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
+ aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
+ aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
+
+ // get the font face name
+ aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
+
+ // use the face's style name only if it looks reasonable
+ const wchar_t* pStyleName = rEnumFont.elfStyle;
+ const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
+ const wchar_t* p = pStyleName;
+ for(; *p && (p < pEnd); ++p )
+ if( *p < 0x0020 )
+ break;
+ if( p < pEnd )
+ aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
+
+ // get device specific font attributes
+ aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
+ aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+
+ aDFA.mbEmbeddable = false;
+ aDFA.mbSubsettable = false;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
+ || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
+ aDFA.mbSubsettable = true;
+ else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
+ aDFA.mbEmbeddable = true;
+
+ // heuristics for font quality
+ // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
+ // - subsetting > embedding > none
+ aDFA.mnQuality = 0;
+ if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
+ aDFA.mnQuality += 50;
+ if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
+ aDFA.mnQuality += 10;
+ if( aDFA.mbSubsettable )
+ aDFA.mnQuality += 200;
+ else if( aDFA.mbEmbeddable )
+ aDFA.mnQuality += 100;
+
+ // #i38665# prefer Type1 versions of the standard postscript fonts
+ if( aDFA.mbEmbeddable )
+ {
+ if( aDFA.maName.EqualsAscii( "AvantGarde" )
+ || aDFA.maName.EqualsAscii( "Bookman" )
+ || aDFA.maName.EqualsAscii( "Courier" )
+ || aDFA.maName.EqualsAscii( "Helvetica" )
+ || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
+ || aDFA.maName.EqualsAscii( "Palatino" )
+ || aDFA.maName.EqualsAscii( "Symbol" )
+ || aDFA.maName.EqualsAscii( "Times" )
+ || aDFA.maName.EqualsAscii( "ZapfChancery" )
+ || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
+ aDFA.mnQuality += 500;
+ }
+
+ // TODO: add alias names
+ return aDFA;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICA* pMetric,
+ DWORD nFontType )
+{
+ int nHeight = 0;
+ if ( nFontType & RASTER_FONTTYPE )
+ nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
+
+ ImplWinFontData* pData = new ImplWinFontData(
+ WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
+ nHeight,
+ pLogFont->elfLogFont.lfCharSet,
+ pMetric->tmPitchAndFamily );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
+ const NEWTEXTMETRICW* pMetric,
+ DWORD nFontType )
+{
+ int nHeight = 0;
+ if ( nFontType & RASTER_FONTTYPE )
+ nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
+
+ ImplWinFontData* pData = new ImplWinFontData(
+ WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
+ nHeight,
+ pLogFont->elfLogFont.lfCharSet,
+ pMetric->tmPitchAndFamily );
+
+ return pData;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
+{
+ String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
+ if ( aFontName.Len() )
+ {
+ rFont.SetName( aFontName );
+ rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
+ rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
+
+ long nFontHeight = rLogFont.lfHeight;
+ if ( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+ if( !nDPIY )
+ nDPIY = 600;
+ nFontHeight *= 72;
+ nFontHeight += nDPIY/2;
+ nFontHeight /= nDPIY;
+ rFont.SetSize( Size( 0, nFontHeight ) );
+ rFont.SetOrientation( (short)rLogFont.lfEscapement );
+ if ( rLogFont.lfItalic )
+ rFont.SetItalic( ITALIC_NORMAL );
+ else
+ rFont.SetItalic( ITALIC_NONE );
+ if ( rLogFont.lfUnderline )
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+ else
+ rFont.SetUnderline( UNDERLINE_NONE );
+ if ( rLogFont.lfStrikeOut )
+ rFont.SetStrikeout( STRIKEOUT_SINGLE );
+ else
+ rFont.SetStrikeout( STRIKEOUT_NONE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
+{
+ XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
+ if ( aFontName.Len() )
+ {
+ rFont.SetName( aFontName );
+ rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
+ rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
+ rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
+
+ long nFontHeight = rLogFont.lfHeight;
+ if ( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+ if( !nDPIY )
+ nDPIY = 600;
+ nFontHeight *= 72;
+ nFontHeight += nDPIY/2;
+ nFontHeight /= nDPIY;
+ rFont.SetSize( Size( 0, nFontHeight ) );
+ rFont.SetOrientation( (short)rLogFont.lfEscapement );
+ if ( rLogFont.lfItalic )
+ rFont.SetItalic( ITALIC_NORMAL );
+ else
+ rFont.SetItalic( ITALIC_NONE );
+ if ( rLogFont.lfUnderline )
+ rFont.SetUnderline( UNDERLINE_SINGLE );
+ else
+ rFont.SetUnderline( UNDERLINE_NONE );
+ if ( rLogFont.lfStrikeOut )
+ rFont.SetStrikeout( STRIKEOUT_SINGLE );
+ else
+ rFont.SetStrikeout( STRIKEOUT_NONE );
+ }
+}
+
+// =======================================================================
+
+ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
+ int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
+: ImplFontData( rDFS, 0 ),
+ meWinCharSet( eWinCharSet ),
+ mnPitchAndFamily( nPitchAndFamily ),
+ mpFontCharSets( NULL ),
+ mpUnicodeMap( NULL ),
+ mbGsubRead( false ),
+ mbDisableGlyphApi( false ),
+ mbHasKoreanRange( false ),
+ mbHasCJKSupport( false ),
+#ifdef ENABLE_GRAPHITE
+ mbHasGraphiteSupport( false ),
+#endif
+ mbHasArabicSupport ( false ),
+ mbAliasSymbolsLow( false ),
+ mbAliasSymbolsHigh( false ),
+ mnId( 0 ),
+ mpEncodingVector( NULL )
+{
+ SetBitmapSize( 0, nHeight );
+
+ if( eWinCharSet == SYMBOL_CHARSET )
+ {
+ if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
+ {
+ // truetype fonts need their symbols as U+F0xx
+ mbAliasSymbolsHigh = true;
+ }
+ else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
+ == (TMPF_VECTOR|TMPF_DEVICE) )
+ {
+ // scalable device fonts (e.g. builtin printer fonts)
+ // need their symbols as U+00xx
+ mbAliasSymbolsLow = true;
+ }
+ else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
+ {
+ // bitmap fonts need their symbols as U+F0xx
+ mbAliasSymbolsHigh = true;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplWinFontData::~ImplWinFontData()
+{
+ delete[] mpFontCharSets;
+
+ if( mpUnicodeMap )
+ mpUnicodeMap->DeReference();
+ delete mpEncodingVector;
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplWinFontData::GetFontId() const
+{
+ return mnId;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
+{
+ // short circuit if already initialized
+ if( mpUnicodeMap != NULL )
+ return;
+
+ ReadCmapTable( hDC );
+ ReadOs2Table( hDC );
+#ifdef ENABLE_GRAPHITE
+ static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
+ if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
+ {
+ mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
+ }
+#endif
+
+ // even if the font works some fonts have problems with the glyph API
+ // => the heuristic below tries to figure out which fonts have the problem
+ TEXTMETRICA aTextMetric;
+ if( ::GetTextMetricsA( hDC, &aTextMetric ) )
+ if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
+ || (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
+ mbDisableGlyphApi = true;
+
+#if 0
+ // #110548# more important than #107885# => TODO: better solution
+ DWORD nFLI = GetFontLanguageInfo( hDC );
+ if( 0 == (nFLI & GCP_GLYPHSHAPE) )
+ mbDisableGlyphApi = true;
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
+{
+ if( !mbGsubRead )
+ ReadGsubTable( hDC );
+ return !maGsubTable.empty();
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
+{
+ return( maGsubTable.find( cChar ) != maGsubTable.end() );
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
+{
+ if( !mpUnicodeMap )
+ return NULL;
+ return mpUnicodeMap;
+}
+
+// -----------------------------------------------------------------------
+
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
+//static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
+static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
+
+void ImplWinFontData::ReadOs2Table( HDC hDC ) const
+{
+ const DWORD Os2Tag = CalcTag( "OS/2" );
+ DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
+ if( (nLength == GDI_ERROR) || !nLength )
+ return;
+ std::vector<unsigned char> aOS2map( nLength );
+ unsigned char* pOS2map = &aOS2map[0];
+ ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
+ sal_uInt32 nVersion = GetUShort( pOS2map );
+ if ( nVersion >= 0x0001 && nLength >= 58 )
+ {
+ // We need at least version 0x0001 (TrueType rev 1.66)
+ // to have access to the needed struct members.
+ sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
+ sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+#if 0
+ sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
+ sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
+#endif
+
+ // Check for CJK capabilities of the current font
+ mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
+ mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
+ | (ulUnicodeRange2 & 0x01100000);
+ mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::ReadGsubTable( HDC hDC ) const
+{
+ mbGsubRead = true;
+
+ // check the existence of a GSUB table
+ const DWORD GsubTag = CalcTag( "GSUB" );
+ DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
+ if( (nRC == GDI_ERROR) || !nRC )
+ return;
+
+ // parse the GSUB table through sft
+ // TODO: parse it directly
+
+ // sft needs the full font file data => get it
+ const RawFontData aRawFontData( hDC );
+ if( !aRawFontData.get() )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*aRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ TrueTypeFont* pTTFont = NULL;
+ ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
+ if( !pTTFont )
+ return;
+
+ // add vertically substituted characters to list
+ static const sal_Unicode aGSUBCandidates[] = {
+ 0x0020, 0x0080, // ASCII
+ 0x2000, 0x2600, // misc
+ 0x3000, 0x3100, // CJK punctutation
+ 0x3300, 0x3400, // squared words
+ 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
+ 0 };
+
+ for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
+ for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
+ if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
+ maGsubTable.insert( cChar ); // insert GSUBbed unicodes
+
+ CloseTTFont( pTTFont );
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontData::ReadCmapTable( HDC hDC ) const
+{
+ if( mpUnicodeMap != NULL )
+ return;
+
+ bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
+ // get the CMAP table from the font which is selected into the DC
+ const DWORD nCmapTag = CalcTag( "cmap" );
+ const RawFontData aRawFontData( hDC, nCmapTag );
+ // parse the CMAP table if available
+ if( aRawFontData.get() ) {
+ CmapResult aResult;
+ ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
+ mbDisableGlyphApi |= aResult.mbRecoded;
+ aResult.mbSymbolic = bIsSymbolFont;
+ if( aResult.mnRangeCount > 0 )
+ mpUnicodeMap = new ImplFontCharMap( aResult );
+ }
+
+ if( !mpUnicodeMap )
+ mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
+ mpUnicodeMap->AddReference();
+}
+
+// =======================================================================
+
+void WinSalGraphics::SetTextColor( SalColor nSalColor )
+{
+ COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
+ SALCOLOR_GREEN( nSalColor ),
+ SALCOLOR_BLUE( nSalColor ) );
+
+ if( !mbPrinter &&
+ GetSalData()->mhDitherPal &&
+ ImplIsSysColorEntry( nSalColor ) )
+ {
+ aCol = PALRGB_TO_RGB( aCol );
+ }
+
+ ::SetTextColor( mhDC, aCol );
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
+ const NEWTEXTMETRICEXW*,
+ DWORD, LPARAM lParam )
+{
+ *((bool*)(void*)lParam) = true;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
+ const NEWTEXTMETRICEXA*,
+ DWORD, LPARAM lParam )
+{
+ *((bool*)(void*)lParam) = true;
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
+{
+ // Test, if Font available
+ LOGFONTW aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+
+ UINT nNameLen = rName.Len();
+ if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
+ nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
+ memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
+ aLogFont.lfFaceName[nNameLen] = 0;
+
+ bool bAvailable = false;
+ EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
+ (LPARAM)(void*)&bAvailable, 0 );
+
+ return bAvailable;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplGetLogFontFromFontSelect( HDC hDC,
+ const ImplFontSelectData* pFont,
+ LOGFONTW& rLogFont,
+ bool /*bTestVerticalAvail*/ )
+{
+ UniString aName;
+ if ( pFont->mpFontData )
+ aName = pFont->mpFontData->maName;
+ else
+ aName = pFont->maName.GetToken( 0 );
+
+ UINT nNameLen = aName.Len();
+ if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
+ nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
+ rLogFont.lfFaceName[nNameLen] = 0;
+
+ if( !pFont->mpFontData )
+ {
+ rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
+ rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
+ | ImplFamilyToWin( pFont->meFamily );
+ }
+ else
+ {
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+ rLogFont.lfCharSet = pWinFontData->GetCharSet();
+ rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
+ }
+
+ rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
+ rLogFont.lfHeight = (LONG)-pFont->mnHeight;
+ rLogFont.lfWidth = (LONG)pFont->mnWidth;
+ rLogFont.lfUnderline = 0;
+ rLogFont.lfStrikeOut = 0;
+ rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
+ rLogFont.lfEscapement = pFont->mnOrientation;
+ rLogFont.lfOrientation = rLogFont.lfEscapement;
+ rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ rLogFont.lfQuality = DEFAULT_QUALITY;
+ rLogFont.lfOutPrecision = OUT_TT_PRECIS;
+ if ( pFont->mnOrientation )
+ rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
+
+ // disable antialiasing if requested
+ if ( pFont->mbNonAntialiased )
+ rLogFont.lfQuality = NONANTIALIASED_QUALITY;
+
+ // select vertical mode if requested and available
+ if( pFont->mbVertical && nNameLen )
+ {
+ // vertical fonts start with an '@'
+ memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
+ sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
+ rLogFont.lfFaceName[0] = '@';
+
+ // check availability of vertical mode for this font
+ bool bAvailable = false;
+ EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
+ (LPARAM)&bAvailable, 0 );
+
+ if( !bAvailable )
+ {
+ // restore non-vertical name if not vertical mode isn't available
+ memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetLogFontFromFontSelect( HDC hDC,
+ const ImplFontSelectData* pFont,
+ LOGFONTA& rLogFont,
+ bool /*bTestVerticalAvail*/ )
+{
+ ByteString aName;
+ if( pFont->mpFontData )
+ aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
+ else
+ aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
+
+ int nNameLen = aName.Len();
+ if( nNameLen > LF_FACESIZE )
+ nNameLen = LF_FACESIZE;
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+
+ if( !pFont->mpFontData )
+ {
+ rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
+ rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
+ | ImplFamilyToWin( pFont->meFamily );
+ }
+ else
+ {
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+ rLogFont.lfCharSet = pWinFontData->GetCharSet();
+ rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
+ }
+
+ rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
+ rLogFont.lfHeight = (LONG)-pFont->mnHeight;
+ rLogFont.lfWidth = (LONG)pFont->mnWidth;
+ rLogFont.lfUnderline = 0;
+ rLogFont.lfStrikeOut = 0;
+ rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
+ rLogFont.lfEscapement = pFont->mnOrientation;
+ rLogFont.lfOrientation = rLogFont.lfEscapement; // ignored by W98
+ rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ rLogFont.lfQuality = DEFAULT_QUALITY;
+ rLogFont.lfOutPrecision = OUT_TT_PRECIS;
+ if( pFont->mnOrientation )
+ rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
+
+ // disable antialiasing if requested
+ if( pFont->mbNonAntialiased )
+ rLogFont.lfQuality = NONANTIALIASED_QUALITY;
+
+ // select vertical mode if requested and available
+ if( pFont->mbVertical && nNameLen )
+ {
+ // vertical fonts start with an '@'
+ memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
+ sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
+ rLogFont.lfFaceName[0] = '@';
+
+ // check availability of vertical mode for this font
+ bool bAvailable = false;
+ EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
+ (LPARAM)&bAvailable, 0 );
+
+ if( !bAvailable )
+ {
+ // restore non-vertical name if vertical mode is not supported
+ memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
+ if( nNameLen < LF_FACESIZE )
+ rLogFont.lfFaceName[nNameLen] = '\0';
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
+{
+ HFONT hNewFont = 0;
+
+ HDC hdcScreen = 0;
+ if( mbVirDev )
+ // only required for virtual devices, see below for details
+ hdcScreen = GetDC(0);
+
+ if( true/*aSalShlData.mbWNT*/ )
+ {
+ LOGFONTW aLogFont;
+ ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
+
+ // on the display we prefer Courier New when Courier is a
+ // bitmap only font and we need to stretch or rotate it
+ if( mbScreen
+ && (i_pFont->mnWidth != 0
+ || i_pFont->mnOrientation != 0
+ || i_pFont->mpFontData == NULL
+ || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
+ && !bImplSalCourierScalable
+ && bImplSalCourierNew
+ && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
+ lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
+
+ // #i47675# limit font requests to MAXFONTHEIGHT
+ // TODO: share MAXFONTHEIGHT font instance
+ if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
+ && (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
+ {
+ o_rFontScale = 1.0;
+ }
+ else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
+ {
+ o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
+ aLogFont.lfHeight = -MAXFONTHEIGHT;
+ aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
+ }
+ else // #i95867# also limit font widths
+ {
+ o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
+ aLogFont.lfWidth = +MAXFONTHEIGHT;
+ aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
+ }
+
+ hNewFont = ::CreateFontIndirectW( &aLogFont );
+ if( hdcScreen )
+ {
+ // select font into screen hdc first to get an antialiased font
+ // see knowledge base article 305290:
+ // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
+ SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
+ }
+ o_rOldFont = ::SelectFont( mhDC, hNewFont );
+
+ TEXTMETRICW aTextMetricW;
+ if( !::GetTextMetricsW( mhDC, &aTextMetricW ) )
+ {
+ // the selected font doesn't work => try a replacement
+ // TODO: use its font fallback instead
+ lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
+ aLogFont.lfPitchAndFamily = FIXED_PITCH;
+ HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
+ SelectFont( mhDC, hNewFont2 );
+ DeleteFont( hNewFont );
+ hNewFont = hNewFont2;
+ }
+ }
+
+ if( hdcScreen )
+ ::ReleaseDC( NULL, hdcScreen );
+
+ return hNewFont;
+}
+
+sal_uInt16 WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
+{
+ // return early if there is no new font
+ if( !pFont )
+ {
+ // deselect still active font
+ if( mhDefFont )
+ ::SelectFont( mhDC, mhDefFont );
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ ::DeleteFont( mhFonts[i] );
+ mhFonts[ i ] = 0;
+ }
+ mhDefFont = 0;
+ return 0;
+ }
+
+ DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
+ mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
+ mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
+
+ HFONT hOldFont = 0;
+ HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
+
+ if( !mhDefFont )
+ {
+ // keep default font
+ mhDefFont = hOldFont;
+ }
+ else
+ {
+ // release no longer referenced font handles
+ for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
+ {
+ if( mhFonts[i] )
+ {
+ ::DeleteFont( mhFonts[i] );
+ mhFonts[i] = 0;
+ }
+ }
+ }
+
+ // store new font in correct layer
+ mhFonts[ nFallbackLevel ] = hNewFont;
+ // now the font is live => update font face
+ if( mpWinFontData[ nFallbackLevel ] )
+ mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( mhDC );
+
+ if( !nFallbackLevel )
+ {
+ mbFontKernInit = TRUE;
+ if ( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+ }
+
+ mnFontCharSetCount = 0;
+
+ // some printers have higher internal resolution, so their
+ // text output would be different from what we calculated
+ // => suggest DrawTextArray to workaround this problem
+ if ( mbPrinter )
+ return SAL_SETFONT_USEDRAWTEXTARRAY;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
+{
+ // temporarily change the HDC to the font in the fallback level
+ HFONT hOldFont = SelectFont( mhDC, mhFonts[nFallbackLevel] );
+
+ wchar_t aFaceName[LF_FACESIZE+60];
+ if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
+ pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
+
+ // get the font metric
+ TEXTMETRICA aWinMetric;
+ const bool bOK = GetTextMetricsA( mhDC, &aWinMetric );
+ // restore the HDC to the font in the base level
+ SelectFont( mhDC, hOldFont );
+ if( !bOK )
+ return;
+
+ // device independent font attributes
+ pMetric->meFamily = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
+ pMetric->mbSymbolFlag = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
+ pMetric->meWeight = ImplWeightToSal( aWinMetric.tmWeight );
+ pMetric->mePitch = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
+ pMetric->meItalic = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
+ pMetric->mnSlant = 0;
+
+ // device dependend font attributes
+ pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
+ pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
+ if( pMetric->mbScalableFont )
+ {
+ // check if there are kern pairs
+ // TODO: does this work with GPOS kerning?
+ DWORD nKernPairs = ::GetKerningPairsA( mhDC, 0, NULL );
+ pMetric->mbKernableFont = (nKernPairs > 0);
+ }
+ else
+ {
+ // bitmap fonts cannot be rotated directly
+ pMetric->mnOrientation = 0;
+ // bitmap fonts have no kerning
+ pMetric->mbKernableFont = false;
+ }
+
+ // transformation dependend font metrics
+ pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
+ pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
+ pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
+ pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
+ pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
+
+ // #107888# improved metric compatibility for Asian fonts...
+ // TODO: assess workaround below for CWS >= extleading
+ // TODO: evaluate use of aWinMetric.sTypo* members for CJK
+ if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() )
+ {
+ pMetric->mnIntLeading += pMetric->mnExtLeading;
+
+ // #109280# The line height for Asian fonts is too small.
+ // Therefore we add half of the external leading to the
+ // ascent, the other half is added to the descent.
+ const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
+ const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
+
+ // #110641# external leading for Asian fonts.
+ // The factor 0.3 has been confirmed with experiments.
+ long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
+ nCJKExtLeading -= pMetric->mnExtLeading;
+ pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
+
+ pMetric->mnAscent += nHalfTmpExtLeading;
+ pMetric->mnDescent += nOtherHalfTmpExtLeading;
+ }
+
+ pMetric->mnMinKashida = GetMinKashidaWidth();
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICEXA* /*pMetric*/,
+ DWORD /*nFontType*/, LPARAM lParam )
+{
+ WinSalGraphics* pData = (WinSalGraphics*)lParam;
+ // Charset already in the list?
+ for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
+ {
+ if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
+ return 1;
+ }
+ pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
+ pData->mnFontCharSetCount++;
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetAllFontCharSets( WinSalGraphics* pData )
+{
+ if ( !pData->mpFontCharSets )
+ pData->mpFontCharSets = new BYTE[256];
+
+ LOGFONTA aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+ GetTextFaceA( pData->mhDC, sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
+ EnumFontFamiliesExA( pData->mhDC, &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
+ (LPARAM)(void*)pData, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplAddKerningPairs( WinSalGraphics* pData )
+{
+ sal_uLong nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL );
+ if ( !nPairs )
+ return;
+
+ CHARSETINFO aInfo;
+ if ( !TranslateCharsetInfo( (DWORD*)(sal_uLong)GetTextCharset( pData->mhDC ), &aInfo, TCI_SRCCHARSET ) )
+ return;
+
+ if ( !pData->mpFontKernPairs )
+ pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
+ else
+ {
+ KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
+ pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
+ memcpy( pData->mpFontKernPairs, pOldPairs,
+ pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
+ delete[] pOldPairs;
+ }
+
+ UINT nCP = aInfo.ciACP;
+ sal_uLong nOldPairs = pData->mnFontKernPairCount;
+ KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
+ nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair );
+ for ( sal_uLong i = 0; i < nPairs; i++ )
+ {
+ unsigned char aBuf[2];
+ wchar_t nChar;
+ int nLen;
+ sal_Bool bAdd = TRUE;
+
+ // None-ASCII?, then we must convert the char
+ if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
+ {
+ if ( pTempPair->wFirst < 256 )
+ {
+ aBuf[0] = (unsigned char)pTempPair->wFirst;
+ nLen = 1;
+ }
+ else
+ {
+ aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
+ aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
+ nLen = 2;
+ }
+ if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
+ (const char*)aBuf, nLen, &nChar, 1 ) )
+ pTempPair->wFirst = nChar;
+ else
+ bAdd = FALSE;
+ }
+ if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
+ {
+ if ( pTempPair->wSecond < 256 )
+ {
+ aBuf[0] = (unsigned char)pTempPair->wSecond;
+ nLen = 1;
+ }
+ else
+ {
+ aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
+ aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
+ nLen = 2;
+ }
+ if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
+ (const char*)aBuf, nLen, &nChar, 1 ) )
+ pTempPair->wSecond = nChar;
+ else
+ bAdd = FALSE;
+ }
+
+ // TODO: get rid of linear search!
+ KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
+ for ( sal_uLong j = 0; j < nOldPairs; j++ )
+ {
+ if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
+ (pTempPair2->wSecond == pTempPair->wSecond) )
+ {
+ bAdd = FALSE;
+ break;
+ }
+ pTempPair2++;
+ }
+
+ if ( bAdd )
+ {
+ KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
+ if ( pDestPair != pTempPair )
+ memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
+ pData->mnFontKernPairCount++;
+ }
+
+ pTempPair++;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong WinSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs )
+{
+ DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
+ "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
+
+ if ( mbFontKernInit )
+ {
+ if( mpFontKernPairs )
+ {
+ delete[] mpFontKernPairs;
+ mpFontKernPairs = NULL;
+ }
+ mnFontKernPairCount = 0;
+
+ KERNINGPAIR* pPairs = NULL;
+ int nCount = ::GetKerningPairsW( mhDC, 0, NULL );
+ if( nCount )
+ {
+ #ifdef GCP_KERN_HACK
+ pPairs = new KERNINGPAIR[ nCount+1 ];
+ mpFontKernPairs = pPairs;
+ mnFontKernPairCount = nCount;
+ ::GetKerningPairsW( mhDC, nCount, pPairs );
+ #else // GCP_KERN_HACK
+ pPairs = pKernPairs;
+ nCount = (nCount < nPairs) : nCount : nPairs;
+ ::GetKerningPairsW( mhDC, nCount, pPairs );
+ return nCount;
+ #endif // GCP_KERN_HACK
+ }
+
+ mbFontKernInit = FALSE;
+
+ std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
+ }
+
+ if( !pKernPairs )
+ return mnFontKernPairCount;
+ else if( mpFontKernPairs )
+ {
+ if ( nPairs < mnFontKernPairCount )
+ nPairs = mnFontKernPairCount;
+ memcpy( pKernPairs, mpFontKernPairs,
+ nPairs*sizeof( ImplKernPairData ) );
+ return nPairs;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
+{
+ if( !mpWinFontData[0] )
+ return ImplFontCharMap::GetDefaultMap();
+ return mpWinFontData[0]->GetImplFontCharMap();
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
+ const NEWTEXTMETRICEXA* pMetric,
+ DWORD nFontType, LPARAM lParam )
+{
+ ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
+ if ( !pInfo->mpName )
+ {
+ // Ignore vertical fonts
+ if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
+ {
+ if ( !pInfo->mbImplSalCourierNew )
+ pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
+ if ( !pInfo->mbImplSalCourierScalable )
+ pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
+ else
+ pInfo->mbCourier = FALSE;
+ String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
+ pInfo->mpName = &aName;
+ strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
+ pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
+ EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
+ (LPARAM)(void*)pInfo, 0 );
+ pInfo->mpLogFontA->lfFaceName[0] = '\0';
+ pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
+ pInfo->mpName = NULL;
+ pInfo->mbCourier = FALSE;
+ }
+ }
+ else
+ {
+ // ignore non-scalable non-device font on printer
+ if( pInfo->mbPrinter )
+ if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
+ return 1;
+
+ ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
+ pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
+
+ // prefer the system character set, so that we get as much as
+ // possible important characters. In the other case we could only
+ // display a limited set of characters (#87309#)
+ if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
+ pData->mnQuality += 100;
+
+ // knowing Courier to be scalable is nice
+ if( pInfo->mbCourier )
+ pInfo->mbImplSalCourierScalable |= pData->IsScalable();
+
+ pInfo->mpList->Add( pData );
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
+ const NEWTEXTMETRICEXW* pMetric,
+ DWORD nFontType, LPARAM lParam )
+{
+ ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
+ if ( !pInfo->mpName )
+ {
+ // Ignore vertical fonts
+ if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
+ {
+ if ( !pInfo->mbImplSalCourierNew )
+ pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
+ if ( !pInfo->mbImplSalCourierScalable )
+ pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
+ else
+ pInfo->mbCourier = FALSE;
+ String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
+ pInfo->mpName = &aName;
+ memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
+ pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
+ EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
+ (LPARAM)(void*)pInfo, 0 );
+ pInfo->mpLogFontW->lfFaceName[0] = '\0';
+ pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
+ pInfo->mpName = NULL;
+ pInfo->mbCourier = FALSE;
+ }
+ }
+ else
+ {
+ // ignore non-scalable non-device font on printer
+ if( pInfo->mbPrinter )
+ if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
+ return 1;
+
+ ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
+ pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
+
+ // knowing Courier to be scalable is nice
+ if( pInfo->mbCourier )
+ pInfo->mbImplSalCourierScalable |= pData->IsScalable();
+
+ pInfo->mpList->Add( pData );
+ }
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------
+
+struct TempFontItem
+{
+ ::rtl::OUString maFontFilePath;
+ ::rtl::OString maResourcePath;
+ TempFontItem* mpNextItem;
+};
+
+#ifdef FR_PRIVATE
+static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
+{
+ typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
+
+ static AddFontResourceExW_FUNC pFunc = NULL;
+ static HMODULE hmGDI = NULL;
+
+ if ( !pFunc && !hmGDI )
+ {
+ hmGDI = GetModuleHandleA( "GDI32" );
+ if ( hmGDI )
+ pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
+ }
+
+ if ( pFunc )
+ return pFunc( lpszfileName, fl, pdv );
+ else
+ {
+ SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+ return 0;
+ }
+}
+#endif
+
+bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
+{
+ int nRet = 0;
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+#ifdef FR_PRIVATE
+ nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
+#endif
+
+ if ( !nRet )
+ {
+ static int nCounter = 0;
+ char aFileName[] = "soAA.fot";
+ aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
+ aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
+ char aResourceName[512];
+ int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
+ int nLen = ::GetTempPathA( nMaxLen, aResourceName );
+ ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
+ // security: end buffer in any case
+ aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
+ ::DeleteFileA( aResourceName );
+
+ rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
+ // TODO: font should be private => need to investigate why it doesn't work then
+ if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
+ return false;
+ ++nCounter;
+
+ nRet = ::AddFontResourceA( aResourceName );
+ if( nRet > 0 )
+ {
+ TempFontItem* pNewItem = new TempFontItem;
+ pNewItem->maResourcePath = rtl::OString( aResourceName );
+ pNewItem->maFontFilePath = aUSytemPath.getStr();
+ pNewItem->mpNextItem = rSalData.mpTempFontItem;
+ rSalData.mpTempFontItem = pNewItem;
+ }
+ }
+
+ return (nRet > 0);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplReleaseTempFonts( SalData& rSalData )
+{
+ int nCount = 0;
+ while( TempFontItem* p = rSalData.mpTempFontItem )
+ {
+ ++nCount;
+ if( p->maResourcePath.getLength() )
+ {
+ const char* pResourcePath = p->maResourcePath.getStr();
+ ::RemoveFontResourceA( pResourcePath );
+ ::DeleteFileA( pResourcePath );
+ }
+ else
+ {
+ ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
+ }
+
+ rSalData.mpTempFontItem = p->mpNextItem;
+ delete p;
+ }
+
+#ifndef FR_PRIVATE
+ // notify every other application
+ // unless the temp fonts were installed as private fonts
+ if( nCount > 0 )
+ ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
+#endif // FR_PRIVATE
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
+ ImplDevFontAttributes& rDFA )
+{
+ ::rtl::OUString aUSytemPath;
+ OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+ // get FontAttributes from a *fot file
+ // TODO: use GetTTGlobalFontInfo() to access the font directly
+ rDFA.mnQuality = 1000;
+ rDFA.mbDevice = true;
+ rDFA.meFamily = FAMILY_DONTKNOW;
+ rDFA.meWidthType = WIDTH_DONTKNOW;
+ rDFA.meWeight = WEIGHT_DONTKNOW;
+ rDFA.meItalic = ITALIC_DONTKNOW;
+ rDFA.mePitch = PITCH_DONTKNOW;;
+ rDFA.mbSubsettable= true;
+ rDFA.mbEmbeddable = false;
+
+ // Create temporary file name
+ char aFileName[] = "soAAT.fot";
+ char aResourceName[512];
+ int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
+ int nLen = ::GetTempPathA( nMaxLen, aResourceName );
+ ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
+ ::DeleteFileA( aResourceName );
+
+ // Create font resource file (typically with a .fot file name extension).
+ rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
+ ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
+ ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
+
+ // Open and read the font resource file
+ rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
+ osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
+ osl::File aFotFile( aFotFileName );
+ osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
+ if( aError != osl::FileBase::E_None )
+ return false;
+
+ sal_uInt64 nBytesRead = 0;
+ char aBuffer[4096];
+ aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
+ // clean up temporary resource file
+ aFotFile.close();
+ ::DeleteFileA( aResourceName );
+
+ // retrieve font family name from byte offset 0x4F6
+ int i = 0x4F6;
+ int nNameOfs = i;
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ // skip full name
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ // retrieve font style name
+ int nStyleOfs = i;
+ while( (i < nBytesRead) && (aBuffer[i++] != 0) );
+ if( i >= nBytesRead )
+ return false;
+
+ // convert byte strings to unicode
+ rDFA.maName = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
+ rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
+
+ // byte offset 0x4C7: OS2_fsSelection
+ const char nFSS = aBuffer[ 0x4C7 ];
+ if( nFSS & 0x01 ) // italic
+ rDFA.meItalic = ITALIC_NORMAL;
+ //if( nFSS & 0x20 ) // bold
+ // rDFA.meWeight = WEIGHT_BOLD;
+ if( nFSS & 0x40 ) // regular
+ {
+ rDFA.meWeight = WEIGHT_NORMAL;
+ rDFA.meItalic = ITALIC_NONE;
+ }
+
+ // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
+ int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
+ rDFA.meWeight = ImplWeightToSal( nWinWeight );
+
+ rDFA.mbSymbolFlag = false; // TODO
+ rDFA.mePitch = PITCH_DONTKNOW; // TODO
+
+ // byte offset 0x4DE: pitch&family
+ rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
+
+ // byte offsets 0x4C8/0x4C9: emunits
+ // byte offsets 0x4CE/0x4CF: winascent
+ // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
+ // byte offsets 0x4DF/0x4E0: avgwidth
+ //...
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
+ const String& rFontFileURL, const String& rFontName )
+{
+ RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
+
+ ImplDevFontAttributes aDFA;
+ aDFA.maName = rFontName;
+ aDFA.mnQuality = 1000;
+ aDFA.mbDevice = true;
+
+ // Search Font Name in Cache
+ if( !rFontName.Len() && mpFontAttrCache )
+ aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
+
+ // Retrieve font name from font resource
+ if( !aDFA.maName.Len() )
+ {
+ ImplGetFontAttrFromFile( rFontFileURL, aDFA );
+ if( mpFontAttrCache && aDFA.maName.Len() )
+ mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
+ }
+
+ if ( !aDFA.maName.Len() )
+ return false;
+
+ // remember temp font for cleanup later
+ if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
+ return false;
+
+ UINT nPreferedCharSet = DEFAULT_CHARSET;
+
+ // create matching FontData struct
+ aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
+ aDFA.meFamily = FAMILY_DONTKNOW;
+ aDFA.meWidthType = WIDTH_DONTKNOW;
+ aDFA.meWeight = WEIGHT_DONTKNOW;
+ aDFA.meItalic = ITALIC_DONTKNOW;
+ aDFA.mePitch = PITCH_DONTKNOW;;
+ aDFA.mbSubsettable= true;
+ aDFA.mbEmbeddable = false;
+
+ /*
+ // TODO: improve ImplDevFontAttributes using the "font resource file"
+ aDFS.maName = // using "FONTRES:" from file
+ if( rFontName != aDFS.maName )
+ aDFS.maMapName = aFontName;
+ */
+
+ ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
+ sal::static_int_cast<BYTE>(nPreferedCharSet),
+ sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
+ pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
+ pFontList->Add( pFontData );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+ // make sure all fonts are registered at least temporarily
+ static bool bOnce = true;
+ if( bOnce )
+ {
+ bOnce = false;
+
+ // determine font path
+ // since we are only interested in fonts that could not be
+ // registered before because of missing administration rights
+ // only the font path of the user installation is needed
+ ::rtl::OUString aPath;
+ osl_getExecutableFile( &aPath.pData );
+ ::rtl::OUString aExecutableFile( aPath );
+ aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
+ String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
+ aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/Basis/share/fonts/truetype") );
+
+ // collect fonts in font path that could not be registered
+ osl::Directory aFontDir( aFontDirUrl );
+ osl::FileBase::RC rcOSL = aFontDir.open();
+ if( rcOSL == osl::FileBase::E_None )
+ {
+ osl::DirectoryItem aDirItem;
+ String aEmptyString;
+
+ ::rtl::OUString aBootStrap;
+ rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap );
+ aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ rtl::Bootstrap aBootstrap( aBootStrap );
+ ::rtl::OUString aUserPath;
+ aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
+ String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
+ mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
+
+ while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
+ {
+ osl::FileStatus aFileStatus( FileStatusMask_FileURL );
+ rcOSL = aDirItem.getFileStatus( aFileStatus );
+ if ( rcOSL == osl::FileBase::E_None )
+ AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
+ }
+
+ delete mpFontAttrCache; // destructor rewrites the cache file if needed
+ mpFontAttrCache = NULL;
+ }
+ }
+
+ ImplEnumInfo aInfo;
+ aInfo.mhDC = mhDC;
+ aInfo.mpList = pFontList;
+ aInfo.mpName = NULL;
+ aInfo.mpLogFontA = NULL;
+ aInfo.mpLogFontW = NULL;
+ aInfo.mbCourier = false;
+ aInfo.mbPrinter = mbPrinter;
+ aInfo.mnFontCount = 0;
+ if ( !mbPrinter )
+ {
+ aInfo.mbImplSalCourierScalable = false;
+ aInfo.mbImplSalCourierNew = false;
+ }
+ else
+ {
+ aInfo.mbImplSalCourierScalable = true;
+ aInfo.mbImplSalCourierNew = true;
+ }
+
+ aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
+ DWORD nCP = GetACP();
+ CHARSETINFO aCharSetInfo;
+ if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
+ aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
+
+ LOGFONTW aLogFont;
+ memset( &aLogFont, 0, sizeof( aLogFont ) );
+ aLogFont.lfCharSet = DEFAULT_CHARSET;
+ aInfo.mpLogFontW = &aLogFont;
+ EnumFontFamiliesExW( mhDC, &aLogFont,
+ (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
+
+ // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
+ // um in SetFont() evt. Courier auf Courier New zu mappen
+ if ( !mbPrinter )
+ {
+ bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
+ bImplSalCourierNew = aInfo.mbImplSalCourierNew;
+ }
+
+ // set glyph fallback hook
+ static WinGlyphFallbackSubstititution aSubstFallback( mhDC );
+ pFontList->SetFallbackHook( &aSubstFallback );
+}
+
+// ----------------------------------------------------------------------------
+
+void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
+{}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
+{
+ HDC hDC = mhDC;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_METRICS;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGM;
+ aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
+ aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
+ DWORD nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
+ if( nSize == GDI_ERROR )
+ return false;
+
+ rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
+ Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
+ rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
+ rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
+ rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
+ rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalGraphics::GetGlyphOutline( long nIndex,
+ ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
+{
+ rB2DPolyPoly.clear();
+
+ HDC hDC = mhDC;
+
+ // use unity matrix
+ MAT2 aMat;
+ aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
+ aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
+
+ UINT nGGOFlags = GGO_NATIVE;
+ if( !(nIndex & GF_ISCHAR) )
+ nGGOFlags |= GGO_GLYPH_INDEX;
+ nIndex &= GF_IDXMASK;
+
+ GLYPHMETRICS aGlyphMetrics;
+ const DWORD nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
+ if( !nSize1 ) // blank glyphs are ok
+ return TRUE;
+ else if( nSize1 == GDI_ERROR )
+ return FALSE;
+
+ BYTE* pData = new BYTE[ nSize1 ];
+ const DWORD nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags,
+ &aGlyphMetrics, nSize1, pData, &aMat );
+
+ if( nSize1 != nSize2 )
+ return FALSE;
+
+ // TODO: avoid tools polygon by creating B2DPolygon directly
+ int nPtSize = 512;
+ Point* pPoints = new Point[ nPtSize ];
+ BYTE* pFlags = new BYTE[ nPtSize ];
+
+ TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
+ while( (BYTE*)pHeader < pData+nSize2 )
+ {
+ // only outline data is interesting
+ if( pHeader->dwType != TT_POLYGON_TYPE )
+ break;
+
+ // get start point; next start points are end points
+ // of previous segment
+ USHORT nPnt = 0;
+
+ long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
+ long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt++ ] = POLY_NORMAL;
+
+ bool bHasOfflinePoints = false;
+ TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
+ pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
+ while( (BYTE*)pCurve < (BYTE*)pHeader )
+ {
+ int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
+ if( nPtSize < nNeededSize )
+ {
+ Point* pOldPoints = pPoints;
+ BYTE* pOldFlags = pFlags;
+ nPtSize = 2 * nNeededSize;
+ pPoints = new Point[ nPtSize ];
+ pFlags = new BYTE[ nPtSize ];
+ for( USHORT i = 0; i < nPnt; ++i )
+ {
+ pPoints[ i ] = pOldPoints[ i ];
+ pFlags[ i ] = pOldFlags[ i ];
+ }
+ delete[] pOldPoints;
+ delete[] pOldFlags;
+ }
+
+ int i = 0;
+ if( TT_PRIM_LINE == pCurve->wType )
+ {
+ while( i < pCurve->cpfx )
+ {
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ pPoints[ nPnt ] = Point( nX, nY );
+ pFlags[ nPnt ] = POLY_NORMAL;
+ ++nPnt;
+ }
+ }
+ else if( TT_PRIM_QSPLINE == pCurve->wType )
+ {
+ bHasOfflinePoints = true;
+ while( i < pCurve->cpfx )
+ {
+ // get control point of quadratic bezier spline
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+ ++i;
+ Point aControlP( nX, nY );
+
+ // calculate first cubic control point
+ // P0 = 1/3 * (PBeg + 2 * PQControl)
+ nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+0 ] = POLY_CONTROL;
+
+ // calculate endpoint of segment
+ nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
+ nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
+
+ if ( i+1 >= pCurve->cpfx )
+ {
+ // endpoint is either last point in segment => advance
+ ++i;
+ }
+ else
+ {
+ // or endpoint is the middle of two control points
+ nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
+ nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
+ nX = (nX + 1) / 2;
+ nY = (nY + 1) / 2;
+ // no need to advance, because the current point
+ // is the control point in next bezier spline
+ }
+
+ pPoints[ nPnt+2 ] = Point( nX, nY );
+ pFlags[ nPnt+2 ] = POLY_NORMAL;
+
+ // calculate second cubic control point
+ // P1 = 1/3 * (PEnd + 2 * PQControl)
+ nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
+ nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
+ pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
+ pFlags[ nPnt+1 ] = POLY_CONTROL;
+
+ nPnt += 3;
+ }
+ }
+
+ // next curve segment
+ pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
+ }
+
+ // end point is start point for closed contour
+ // disabled, because Polygon class closes the contour itself
+ // pPoints[nPnt++] = pPoints[0];
+ // #i35928#
+ // Added again, but add only when not yet closed
+ if(pPoints[nPnt - 1] != pPoints[0])
+ {
+ if( bHasOfflinePoints )
+ pFlags[nPnt] = pFlags[0];
+
+ pPoints[nPnt++] = pPoints[0];
+ }
+
+ // convert y-coordinates W32 -> VCL
+ for( int i = 0; i < nPnt; ++i )
+ pPoints[i].Y() = -pPoints[i].Y();
+
+ // insert into polypolygon
+ Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
+ // convert to B2DPolyPolygon
+ // TODO: get rid of the intermediate PolyPolygon
+ rB2DPolyPoly.append( aPoly.getB2DPolygon() );
+ }
+
+ delete[] pPoints;
+ delete[] pFlags;
+
+ delete[] pData;
+
+ // rescaling needed for the PolyPolygon conversion
+ if( rB2DPolyPoly.count() )
+ {
+ const double fFactor(mfFontScale/256);
+ rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+class ScopedFont
+{
+public:
+ explicit ScopedFont(WinSalGraphics & rData);
+
+ ~ScopedFont();
+
+private:
+ WinSalGraphics & m_rData;
+ HFONT m_hOrigFont;
+};
+
+ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
+{
+ m_hOrigFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = 0; // avoid deletion of current font
+}
+
+ScopedFont::~ScopedFont()
+{
+ if( m_hOrigFont )
+ {
+ // restore original font, destroy temporary font
+ HFONT hTempFont = m_rData.mhFonts[0];
+ m_rData.mhFonts[0] = m_hOrigFont;
+ SelectObject( m_rData.mhDC, m_hOrigFont );
+ DeleteObject( hTempFont );
+ }
+}
+
+class ScopedTrueTypeFont
+{
+public:
+ inline ScopedTrueTypeFont(): m_pFont(0) {}
+
+ ~ScopedTrueTypeFont();
+
+ int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
+
+ inline TrueTypeFont * get() const { return m_pFont; }
+
+private:
+ TrueTypeFont * m_pFont;
+};
+
+ScopedTrueTypeFont::~ScopedTrueTypeFont()
+{
+ if (m_pFont != 0)
+ CloseTTFont(m_pFont);
+}
+
+int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
+ sal_uInt32 nFaceNum)
+{
+ OSL_ENSURE(m_pFont == 0, "already open");
+ return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
+}
+
+sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
+ const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
+ sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
+{
+ // TODO: use more of the central font-subsetting code, move stuff there if needed
+
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ // use height=1000 for easier debugging (to match psprint's font units)
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ float fScale = 1.0;
+ HFONT hOldFont = 0;
+ ImplDoSetFont( &aIFSD, fScale, hOldFont );
+
+ ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
+
+#if OSL_DEBUG_LEVEL > 1
+ // get font metrics
+ TEXTMETRICA aWinMetric;
+ if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
+ return FALSE;
+
+ DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
+ DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
+#endif
+
+ rtl::OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
+ return FALSE;
+ const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
+ const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
+
+ // check if the font has a CFF-table
+ const DWORD nCffTag = CalcTag( "CFF " );
+ const RawFontData aRawCffData( mhDC, nCffTag );
+ if( aRawCffData.get() )
+ {
+ pWinFontData->UpdateFromHDC( mhDC );
+ const ImplFontCharMap* pCharMap = pWinFontData->GetImplFontCharMap();
+ pCharMap->AddReference();
+
+ long nRealGlyphIds[ 256 ];
+ for( int i = 0; i < nGlyphCount; ++i )
+ {
+ // TODO: remap notdef glyph if needed
+ // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
+ nGlyphIdx = pCharMap->GetGlyphIndex( nGlyphIdx );
+ if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
+ {/*####*/}
+
+ nRealGlyphIds[i] = nGlyphIdx;
+ }
+
+ pCharMap->DeReference(); // TODO: and and use a RAII object
+
+ // provide a font subset from the CFF-table
+ FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
+ rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
+ bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
+ nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
+ fclose( pOutFile );
+ return bRC;
+ }
+
+ // get raw font file data
+ const RawFontData xRawFontData( mhDC, NULL );
+ if( !xRawFontData.get() )
+ return FALSE;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
+ if( nRC != SF_OK )
+ return FALSE;
+
+ TTGlobalFontInfo aTTInfo;
+ ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
+ rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
+ rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
+ rInfo.m_nAscent = +aTTInfo.winAscent;
+ rInfo.m_nDescent = -aTTInfo.winDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
+ Point( aTTInfo.xMax, aTTInfo.yMax ) );
+ rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
+
+ // subset TTF-glyphs and get their properties
+ // take care that subset fonts require the NotDef glyph in pos 0
+ int nOrigCount = nGlyphCount;
+ sal_uInt16 aShortIDs[ 256 ];
+ sal_uInt8 aTempEncs[ 256 ];
+
+ int nNotDef=-1, i;
+ for( i = 0; i < nGlyphCount; ++i )
+ {
+ aTempEncs[i] = pEncoding[i];
+ sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
+ if( pGlyphIDs[i] & GF_ISCHAR )
+ {
+ sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
+ const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
+ nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
+ if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
+ {
+ // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
+ cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
+ nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
+ }
+ }
+ aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx );
+ if( !nGlyphIdx )
+ if( nNotDef < 0 )
+ nNotDef = i; // first NotDef glyph found
+ }
+
+ if( nNotDef != 0 )
+ {
+ // add fake NotDef glyph if needed
+ if( nNotDef < 0 )
+ nNotDef = nGlyphCount++;
+
+ // NotDef glyph must be in pos 0 => swap glyphids
+ aShortIDs[ nNotDef ] = aShortIDs[0];
+ aTempEncs[ nNotDef ] = aTempEncs[0];
+ aShortIDs[0] = 0;
+ aTempEncs[0] = 0;
+ }
+ DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
+
+ // fill pWidth array
+ TTSimpleGlyphMetrics* pMetrics =
+ ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
+ if( !pMetrics )
+ return FALSE;
+ sal_uInt16 nNotDefAdv = pMetrics[0].adv;
+ pMetrics[0].adv = pMetrics[nNotDef].adv;
+ pMetrics[nNotDef].adv = nNotDefAdv;
+ for( i = 0; i < nOrigCount; ++i )
+ pGlyphWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+
+ // write subset into destination file
+ nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
+ aTempEncs, nGlyphCount, 0, NULL, 0 );
+ return (nRC == SF_OK);
+}
+
+//--------------------------------------------------------------------------
+
+const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
+ const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
+ FontSubsetInfo& rInfo, long* pDataLen )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+ SetFont( &aIFSD, 0 );
+
+ // get the raw font file data
+ RawFontData aRawFontData( mhDC );
+ *pDataLen = aRawFontData.size();
+ if( !aRawFontData.get() )
+ return NULL;
+
+ // get important font properties
+ TEXTMETRICA aTm;
+ if( !::GetTextMetricsA( mhDC, &aTm ) )
+ *pDataLen = 0;
+ const bool bPFA = (*aRawFontData.get() < 0x80);
+ rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
+ WCHAR aFaceName[64];
+ int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName );
+ // #i59854# strip eventual null byte
+ while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
+ nFNLen--;
+ if( nFNLen == 0 )
+ *pDataLen = 0;
+ rInfo.m_aPSName = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<sal_uInt16>(nFNLen) );
+ rInfo.m_nAscent = +aTm.tmAscent;
+ rInfo.m_nDescent = -aTm.tmDescent;
+ rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
+ Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
+ rInfo.m_nCapHeight = aTm.tmAscent; // Well ...
+
+ // get individual character widths
+ for( int i = 0; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ const sal_Unicode cChar = pUnicodes[i];
+ if( !::GetCharWidth32W( mhDC, cChar, cChar, &nCharWidth ) )
+ *pDataLen = 0;
+ pCharWidths[i] = nCharWidth;
+ }
+
+ if( !*pDataLen )
+ return NULL;
+
+ const unsigned char* pData = aRawFontData.steal();
+ return (void*)pData;
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
+{
+ delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
+}
+
+//--------------------------------------------------------------------------
+
+const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
+{
+ // TODO: even for builtin fonts we get here... why?
+ if( !pFont->IsEmbeddable() )
+ return NULL;
+
+ // fill the encoding vector
+ // currently no nonencoded vector
+ if( pNonEncoded )
+ *pNonEncoded = NULL;
+
+ const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
+ const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
+ if( pEncoding == NULL )
+ {
+ Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
+ #if 0
+ // TODO: get correct encoding vector
+ GLYPHSET aGlyphSet;
+ aGlyphSet.cbThis = sizeof(aGlyphSet);
+ DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
+ #else
+ for( sal_Unicode i = 32; i < 256; ++i )
+ (*pNewEncoding)[i] = i;
+ #endif
+ pWinFontData->SetEncodingVector( pNewEncoding );
+ pEncoding = pNewEncoding;
+ }
+
+ return pEncoding;
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc )
+{
+ // create matching ImplFontSelectData
+ // we need just enough to get to the font file data
+ ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
+
+ // TODO: much better solution: move SetFont and restoration of old font to caller
+ ScopedFont aOldFont(*this);
+
+ float fScale = 0.0;
+ HFONT hOldFont = 0;
+ ImplDoSetFont( &aIFSD, fScale, hOldFont );
+
+ if( pFont->IsSubsettable() )
+ {
+ // get raw font file data
+ const RawFontData xRawFontData( mhDC );
+ if( !xRawFontData.get() )
+ return;
+
+ // open font file
+ sal_uInt32 nFaceNum = 0;
+ if( !*xRawFontData.get() ) // TTC candidate
+ nFaceNum = ~0U; // indicate "TTC font extracts only"
+
+ ScopedTrueTypeFont aSftTTF;
+ int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
+ if( nRC != SF_OK )
+ return;
+
+ int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
+ const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
+ pMap->AddReference();
+
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for( int i = 0; i < nCharCount; i++ )
+ {
+ if( nChar < 0x00010000 )
+ {
+ sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
+ static_cast<sal_Ucs>(nChar),
+ bVertical ? 1 : 0 );
+ if( nGlyph )
+ rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
+ }
+ nChar = pMap->GetNextChar( nChar );
+ }
+
+ pMap->DeReference(); // TODO: and and use a RAII object
+ }
+ }
+ else if( pFont->IsEmbeddable() )
+ {
+ // get individual character widths
+ rWidths.clear();
+ rUnicodeEnc.clear();
+ rWidths.reserve( 224 );
+ for( sal_Unicode i = 32; i < 256; ++i )
+ {
+ int nCharWidth = 0;
+ if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
+ {
+ rUnicodeEnc[ i ] = rWidths.size();
+ rWidths.push_back( nCharWidth );
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+
+void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{}
+
+//--------------------------------------------------------------------------
+
+SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
+{
+ SystemFontData aSysFontData;
+
+ if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
+ if (nFallbacklevel < 0 ) nFallbacklevel = 0;
+
+ aSysFontData.nSize = sizeof( SystemFontData );
+ aSysFontData.hFont = mhFonts[nFallbacklevel];
+ aSysFontData.bFakeBold = false;
+ aSysFontData.bFakeItalic = false;
+ aSysFontData.bAntialias = true;
+ aSysFontData.bVerticalCharacterType = false;
+
+ OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
+ aSysFontData.hFont,
+ nFallbacklevel);
+
+ return aSysFontData;
+}
+
+//--------------------------------------------------------------------------
+
diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx
new file mode 100644
index 000000000000..2b46ce47b82d
--- /dev/null
+++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx
@@ -0,0 +1,267 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <tools/svwin.h>
+#include <tools/debug.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salgdi.h>
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+
+#include <GdiPlus.h>
+#include <GdiPlusEnums.h>
+#include <GdiPlusColor.h>
+
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+// -----------------------------------------------------------------------
+
+void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GraphicsPath& rPath, 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));
+ Gdiplus::PointF aFCurr(Gdiplus::REAL(aCurr.getX()), Gdiplus::REAL(aCurr.getY()));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ const sal_uInt32 nNextIndex((a + 1) % nCount);
+ const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const Gdiplus::PointF aFNext(Gdiplus::REAL(aNext.getX()), Gdiplus::REAL(aNext.getY()));
+
+ if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ {
+ const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ rPath.AddBezier(
+ aFCurr,
+ Gdiplus::PointF(Gdiplus::REAL(aCa.getX()), Gdiplus::REAL(aCa.getY())),
+ Gdiplus::PointF(Gdiplus::REAL(aCb.getX()), Gdiplus::REAL(aCb.getY())),
+ aFNext);
+ }
+ else
+ {
+ rPath.AddLine(aFCurr, aFNext);
+ }
+
+ if(a + 1 < nEdgeCount)
+ {
+ aFCurr = aFNext;
+
+ if(bNoLineJoin)
+ {
+ rPath.StartFigure();
+ }
+ }
+ }
+ }
+}
+
+void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GraphicsPath& rPath, 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));
+ Gdiplus::Point aICurr(INT(aCurr.getX()), INT(aCurr.getY()));
+
+ for(sal_uInt32 a(0); a < nEdgeCount; a++)
+ {
+ const sal_uInt32 nNextIndex((a + 1) % nCount);
+ const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex));
+ const Gdiplus::Point aINext(INT(aNext.getX()), INT(aNext.getY()));
+
+ if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex)))
+ {
+ const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a));
+ const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex));
+
+ rPath.AddBezier(
+ aICurr,
+ Gdiplus::Point(INT(aCa.getX()), INT(aCa.getY())),
+ Gdiplus::Point(INT(aCb.getX()), INT(aCb.getY())),
+ aINext);
+ }
+ else
+ {
+ rPath.AddLine(aICurr, aINext);
+ }
+
+ if(a + 1 < nEdgeCount)
+ {
+ aICurr = aINext;
+
+ if(bNoLineJoin)
+ {
+ rPath.StartFigure();
+ }
+ }
+ }
+ }
+}
+
+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::Graphics aGraphics(mhDC);
+ 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::SolidBrush aTestBrush(aTestColor);
+ Gdiplus::GraphicsPath aPath;
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ if(0 != a)
+ {
+ aPath.StartFigure(); // #i101491# not needed for first run
+ }
+
+ impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolyPolygon.getB2DPolygon(a), false);
+ aPath.CloseFigure();
+ }
+
+ if(getAntiAliasB2DDraw())
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.FillPath(&aTestBrush, &aPath);
+ }
+
+ return true;
+}
+
+bool WinSalGraphics::drawPolyLine( const basegfx::B2DPolygon& rPolygon, double fTransparency, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin )
+{
+ const sal_uInt32 nCount(rPolygon.count());
+
+ if(mbPen && nCount)
+ {
+ Gdiplus::Graphics aGraphics(mhDC);
+ 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::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX()));
+ Gdiplus::GraphicsPath aPath;
+ bool bNoLineJoin(false);
+
+ switch(eLineJoin)
+ {
+ default : // basegfx::B2DLINEJOIN_NONE :
+ {
+ if(basegfx::fTools::more(rLineWidths.getX(), 0.0))
+ {
+ bNoLineJoin = true;
+ }
+ break;
+ }
+ case basegfx::B2DLINEJOIN_BEVEL :
+ {
+ aTestPen.SetLineJoin(Gdiplus::LineJoinBevel);
+ break;
+ }
+ case basegfx::B2DLINEJOIN_MIDDLE :
+ case basegfx::B2DLINEJOIN_MITER :
+ {
+ const Gdiplus::REAL aMiterLimit(15.0);
+ aTestPen.SetMiterLimit(aMiterLimit);
+ aTestPen.SetLineJoin(Gdiplus::LineJoinMiter);
+ break;
+ }
+ case basegfx::B2DLINEJOIN_ROUND :
+ {
+ aTestPen.SetLineJoin(Gdiplus::LineJoinRound);
+ break;
+ }
+ }
+
+ if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5))
+ {
+ impAddB2DPolygonToGDIPlusGraphicsPathInteger(aPath, rPolygon, bNoLineJoin);
+ }
+ else
+ {
+ impAddB2DPolygonToGDIPlusGraphicsPathReal(aPath, rPolygon, bNoLineJoin);
+ }
+
+ if(rPolygon.isClosed() && !bNoLineJoin)
+ {
+ // #i101491# needed to create the correct line joins
+ aPath.CloseFigure();
+ }
+
+ if(getAntiAliasB2DDraw())
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+ }
+ else
+ {
+ aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+ }
+
+ aGraphics.DrawPath(&aTestPen, &aPath);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
diff --git a/vcl/win/source/gdi/salnativewidgets-luna.cxx b/vcl/win/source/gdi/salnativewidgets-luna.cxx
new file mode 100755
index 000000000000..0f1b8151967d
--- /dev/null
+++ b/vcl/win/source/gdi/salnativewidgets-luna.cxx
@@ -0,0 +1,1419 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#define _SV_SALNATIVEWIDGETS_CXX
+
+#include "rtl/ustring.h"
+
+#include "osl/module.h"
+
+#include "vcl/svapp.hxx"
+
+#include "win/svsys.h"
+#include "win/salgdi.h"
+#include "win/saldata.hxx"
+
+#include "uxtheme.h"
+#include "vssym32.h"
+
+#include <map>
+#include <string>
+
+using namespace rtl;
+using namespace std;
+
+typedef map< wstring, HTHEME > ThemeMap;
+static ThemeMap aThemeMap;
+
+
+/****************************************************
+ wrap visual styles API to avoid linking against it
+ it is not available on all Windows platforms
+*****************************************************/
+
+class VisualStylesAPI
+{
+private:
+ typedef HTHEME (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList );
+ typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme );
+ typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
+ typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
+ typedef HRESULT (WINAPI * DrawThemeText_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
+ typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
+
+ OpenThemeData_Proc_T lpfnOpenThemeData;
+ CloseThemeData_Proc_T lpfnCloseThemeData;
+ GetThemeBackgroundContentRect_Proc_T lpfnGetThemeBackgroundContentRect;
+ DrawThemeBackground_Proc_T lpfnDrawThemeBackground;
+ DrawThemeText_Proc_T lpfnDrawThemeText;
+ GetThemePartSize_Proc_T lpfnGetThemePartSize;
+
+ oslModule mhModule;
+
+public:
+ VisualStylesAPI();
+ ~VisualStylesAPI();
+ sal_Bool IsAvailable() { return (mhModule != NULL); }
+
+ HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList );
+ HRESULT CloseThemeData( HTHEME hTheme );
+ HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
+ HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
+ HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
+ HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
+};
+
+static VisualStylesAPI vsAPI;
+
+VisualStylesAPI::VisualStylesAPI()
+{
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "uxtheme.dll" ) );
+ mhModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+
+ if ( mhModule )
+ {
+ lpfnOpenThemeData = (OpenThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" );
+ lpfnCloseThemeData = (CloseThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" );
+ lpfnGetThemeBackgroundContentRect = (GetThemeBackgroundContentRect_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" );
+ lpfnDrawThemeBackground = (DrawThemeBackground_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" );
+ lpfnDrawThemeText = (DrawThemeText_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" );
+ lpfnGetThemePartSize = (GetThemePartSize_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" );
+ }
+ else
+ {
+ lpfnOpenThemeData = NULL;
+ lpfnCloseThemeData = NULL;
+ lpfnGetThemeBackgroundContentRect = NULL;
+ lpfnDrawThemeBackground = NULL;
+ lpfnDrawThemeText = NULL;
+ lpfnGetThemePartSize = NULL;
+ }
+}
+VisualStylesAPI::~VisualStylesAPI()
+{
+ if( mhModule )
+ osl_unloadModule( mhModule );
+}
+HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList )
+{
+ if(lpfnOpenThemeData)
+ return (*lpfnOpenThemeData) (hwnd, pszClassList);
+ else
+ return NULL;
+}
+
+HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme )
+{
+ if(lpfnCloseThemeData)
+ return (*lpfnCloseThemeData) (hTheme);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect )
+{
+ if(lpfnGetThemeBackgroundContentRect)
+ return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect );
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect )
+{
+ if(lpfnDrawThemeBackground)
+ return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect )
+{
+ if(lpfnDrawThemeText)
+ return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect);
+ else
+ return S_FALSE;
+}
+HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz )
+{
+ if(lpfnGetThemePartSize)
+ return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz);
+ else
+ return S_FALSE;
+}
+
+
+/*********************************************************
+ * Initialize XP theming and local stuff
+ *********************************************************/
+void SalData::initNWF( void )
+{
+ ImplSVData* pSVData = ImplGetSVData();
+
+ // the menu bar and the top docking area should have a common background (gradient)
+ pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
+}
+
+
+// *********************************************************
+// * Release theming handles
+// ********************************************************
+void SalData::deInitNWF( void )
+{
+ ThemeMap::iterator iter = aThemeMap.begin();
+ while( iter != aThemeMap.end() )
+ {
+ vsAPI.CloseThemeData(iter->second);
+ iter++;
+ }
+ aThemeMap.clear();
+ if( maDwmLib )
+ osl_unloadModule( maDwmLib );
+}
+
+static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name )
+{
+ if( GetSalData()->mbThemeChanged )
+ {
+ // throw away invalid theme handles
+ GetSalData()->deInitNWF();
+ GetSalData()->mbThemeChanged = FALSE;
+ }
+
+ ThemeMap::iterator iter;
+ if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
+ return iter->second;
+ // theme not found -> add it to map
+ HTHEME hTheme = vsAPI.OpenThemeData( hWnd, name );
+ if( hTheme != NULL )
+ aThemeMap[name] = hTheme;
+ return hTheme;
+}
+
+/*
+ * IsNativeControlSupported()
+ *
+ * Returns TRUE if the platform supports native
+ * drawing of the control defined by nPart
+ */
+sal_Bool WinSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
+{
+ HTHEME hTheme = NULL;
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Button");
+ break;
+ case CTRL_SCROLLBAR:
+ if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ return FALSE; // no background painting needed
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Scrollbar");
+ break;
+ case CTRL_COMBOBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_ALL_BUTTONS ||
+ nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN ||
+ nPart == PART_BUTTON_LEFT|| nPart == PART_BUTTON_RIGHT )
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_SPINBUTTONS:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_ALL_BUTTONS )
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ //return TRUE;
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ break;
+ case CTRL_LISTBOX:
+ if( nPart == HAS_BACKGROUND_TEXTURE )
+ return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ hTheme = getThemeHandle( mhWnd, L"Listview");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY:
+ case CTRL_TAB_ITEM:
+ case CTRL_FIXEDBORDER:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Tab");
+ break;
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
+ hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ else
+ // use rebar theme for grip and background
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ else if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nPart == PART_MENU_ITEM )
+ hTheme = getThemeHandle( mhWnd, L"Menu" );
+ }
+ break;
+ case CTRL_MENU_POPUP:
+ if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nPart == PART_ENTIRE_CONTROL ||
+ nPart == PART_MENU_ITEM ||
+ nPart == PART_MENU_ITEM_CHECK_MARK ||
+ nPart == PART_MENU_ITEM_RADIO_MARK ||
+ nPart == PART_MENU_SEPARATOR )
+ hTheme = getThemeHandle( mhWnd, L"Menu" );
+ }
+ break;
+ case CTRL_PROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Progress");
+ break;
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ hTheme = getThemeHandle( mhWnd, L"Trackbar" );
+ break;
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"TreeView" );
+ break;
+ default:
+ hTheme = NULL;
+ break;
+ }
+
+ return (hTheme != NULL);
+}
+
+
+/*
+ * HitTestNativeControl()
+ *
+ * If the return value is TRUE, bIsInside contains information whether
+ * aPos was or was not inside the native widget specified by the
+ * nType/nPart combination.
+ */
+sal_Bool WinSalGraphics::hitTestNativeControl( ControlType,
+ ControlPart,
+ const Rectangle&,
+ const Point&,
+ sal_Bool& )
+{
+ return FALSE;
+}
+
+sal_Bool ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
+{
+ HRESULT hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+
+ if( aStr.getLength() )
+ {
+ RECT rcContent;
+ hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
+ hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState,
+ reinterpret_cast<LPCWSTR>(aStr.getStr()), -1,
+ DT_CENTER | DT_VCENTER | DT_SINGLELINE,
+ 0, &rcContent);
+ }
+ return (hr == S_OK);
+}
+
+
+Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const Rectangle& aRect, THEMESIZE eTS = TS_TRUE )
+{
+ SIZE aSz;
+ RECT rc;
+ rc.left = aRect.nLeft;
+ rc.right = aRect.nRight;
+ rc.top = aRect.nTop;
+ rc.bottom = aRect.nBottom;
+ HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, NULL, eTS, &aSz ); // TS_TRUE returns optimal size
+ if( hr == S_OK )
+ return Rectangle( 0, 0, aSz.cx, aSz.cy );
+ else
+ return Rectangle();
+}
+
+// Helper functions
+// ----
+
+void ImplConvertSpinbuttonValues( int nControlPart, const ControlState& rState, const Rectangle& rRect,
+ int* pLunaPart, int *pLunaState, RECT *pRect )
+{
+ if( nControlPart == PART_BUTTON_DOWN )
+ {
+ *pLunaPart = SPNP_DOWN;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = DNS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = DNS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = DNS_HOT;
+ else
+ *pLunaState = DNS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_UP )
+ {
+ *pLunaPart = SPNP_UP;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = UPS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = UPS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = UPS_HOT;
+ else
+ *pLunaState = UPS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_RIGHT )
+ {
+ *pLunaPart = SPNP_UPHORZ;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = DNHZS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = DNHZS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = DNHZS_HOT;
+ else
+ *pLunaState = DNHZS_NORMAL;
+ }
+ if( nControlPart == PART_BUTTON_LEFT )
+ {
+ *pLunaPart = SPNP_DOWNHORZ;
+ if( rState & CTRL_STATE_PRESSED )
+ *pLunaState = UPHZS_PRESSED;
+ else if( !(rState & CTRL_STATE_ENABLED) )
+ *pLunaState = UPHZS_DISABLED;
+ else if( rState & CTRL_STATE_ROLLOVER )
+ *pLunaState = UPHZS_HOT;
+ else
+ *pLunaState = UPHZS_NORMAL;
+ }
+
+ pRect->left = rRect.Left();
+ pRect->right = rRect.Right()+1;
+ pRect->top = rRect.Top();
+ pRect->bottom = rRect.Bottom()+1;
+}
+
+// ----
+
+sal_Bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
+ ControlType nType,
+ ControlPart nPart,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ OUString aCaption )
+{
+ // a listbox dropdown is actually a combobox dropdown
+ if( nType == CTRL_LISTBOX )
+ if( nPart == PART_BUTTON_DOWN )
+ nType = CTRL_COMBOBOX;
+
+ // draw entire combobox as a large edit box
+ if( nType == CTRL_COMBOBOX )
+ if( nPart == PART_ENTIRE_CONTROL )
+ nType = CTRL_EDITBOX;
+
+ // draw entire spinbox as a large edit box
+ if( nType == CTRL_SPINBOX )
+ if( nPart == PART_ENTIRE_CONTROL )
+ nType = CTRL_EDITBOX;
+
+ int iPart(0), iState(0);
+ if( nType == CTRL_SCROLLBAR )
+ {
+ HRESULT hr;
+ if( nPart == PART_BUTTON_UP )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_UPPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_UPDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_UPHOT;
+ else
+ iState = ABS_UPNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_DOWNPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_DOWNDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_DOWNHOT;
+ else
+ iState = ABS_DOWNNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_LEFT )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_LEFTPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_LEFTDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_LEFTHOT;
+ else
+ iState = ABS_LEFTNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_BUTTON_RIGHT )
+ {
+ iPart = SBP_ARROWBTN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = ABS_RIGHTPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ABS_RIGHTDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ABS_RIGHTHOT;
+ else
+ iState = ABS_RIGHTNORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ iPart = (nPart == PART_THUMB_HORZ) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = SCRBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = SCRBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = SCRBS_HOT;
+ else
+ iState = SCRBS_NORMAL;
+
+ SIZE sz;
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_MIN, &sz);
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_TRUE, &sz);
+ vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_DRAW, &sz);
+
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ // paint gripper on thumb if enough space
+ if( ( (nPart == PART_THUMB_VERT) && (rc.bottom-rc.top > 12) ) ||
+ ( (nPart == PART_THUMB_HORZ) && (rc.right-rc.left > 12) ) )
+ {
+ iPart = (nPart == PART_THUMB_HORZ) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
+ iState = 0;
+ vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ }
+ return (hr == S_OK);
+ }
+ if( nPart == PART_TRACK_HORZ_LEFT || nPart == PART_TRACK_HORZ_RIGHT || nPart == PART_TRACK_VERT_UPPER || nPart == PART_TRACK_VERT_LOWER )
+ {
+ switch( nPart )
+ {
+ case PART_TRACK_HORZ_LEFT: iPart = SBP_UPPERTRACKHORZ; break;
+ case PART_TRACK_HORZ_RIGHT: iPart = SBP_LOWERTRACKHORZ; break;
+ case PART_TRACK_VERT_UPPER: iPart = SBP_UPPERTRACKVERT; break;
+ case PART_TRACK_VERT_LOWER: iPart = SBP_LOWERTRACKVERT; break;
+ }
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = SCRBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = SCRBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = SCRBS_HOT;
+ else
+ iState = SCRBS_NORMAL;
+ hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
+ return (hr == S_OK);
+ }
+ }
+ if( nType == CTRL_SPINBUTTONS && nPart == PART_ALL_BUTTONS )
+ {
+ if( aValue.getType() == CTRL_SPINBUTTONS )
+ {
+ const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);
+ sal_Bool bOk = sal_False;
+
+ RECT rect;
+ ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+
+ if( bOk )
+ {
+ ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+ }
+
+ return bOk;
+ }
+ }
+ if( nType == CTRL_SPINBOX )
+ {
+ // decrease spinbutton rects a little
+ //rc.right--;
+ //rc.bottom--;
+ if( nPart == PART_ALL_BUTTONS )
+ {
+ if( aValue.getType() == CTRL_SPINBUTTONS )
+ {
+ const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);
+ sal_Bool bOk = sal_False;
+
+ RECT rect;
+ ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+
+ if( bOk )
+ {
+ ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
+ bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
+ }
+
+ return bOk;
+ }
+ }
+
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = SPNP_DOWN;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = DNS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = DNS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = DNS_HOT;
+ else
+ iState = DNS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_UP )
+ {
+ iPart = SPNP_UP;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = UPS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = UPS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = UPS_HOT;
+ else
+ iState = UPS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_RIGHT )
+ {
+ iPart = SPNP_DOWNHORZ;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = DNHZS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = DNHZS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = DNHZS_HOT;
+ else
+ iState = DNHZS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_LEFT )
+ {
+ iPart = SPNP_UPHORZ;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = UPHZS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = UPHZS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = UPHZS_HOT;
+ else
+ iState = UPHZS_NORMAL;
+ }
+ if( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT || nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN )
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ if( nType == CTRL_COMBOBOX )
+ {
+ if( nPart == PART_BUTTON_DOWN )
+ {
+ iPart = CP_DROPDOWNBUTTON;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = CBXS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = CBXS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = CBXS_HOT;
+ else
+ iState = CBXS_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+ if( nType == CTRL_PUSHBUTTON )
+ {
+ iPart = BP_PUSHBUTTON;
+ if( nState & CTRL_STATE_PRESSED )
+ iState = PBS_PRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = PBS_DISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = PBS_HOT;
+ else if( nState & CTRL_STATE_DEFAULT )
+ iState = PBS_DEFAULTED;
+ //else if( nState & CTRL_STATE_FOCUSED )
+ // iState = PBS_DEFAULTED; // may need to draw focus rect
+ else
+ iState = PBS_NORMAL;
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_RADIOBUTTON )
+ {
+ iPart = BP_RADIOBUTTON;
+ sal_Bool bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
+ else
+ iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
+
+ //if( nState & CTRL_STATE_FOCUSED )
+ // iState |= PBS_DEFAULTED; // may need to draw focus rect
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_CHECKBOX )
+ {
+ iPart = BP_CHECKBOX;
+ ButtonValue v = aValue.getTristateVal();
+
+ if( nState & CTRL_STATE_PRESSED )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDPRESSED :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
+ else if( !(nState & CTRL_STATE_ENABLED) )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDDISABLED :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDHOT :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
+ else
+ iState = (v == BUTTONVALUE_ON) ? CBS_CHECKEDNORMAL :
+ ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );
+
+ //if( nState & CTRL_STATE_FOCUSED )
+ // iState |= PBS_DEFAULTED; // may need to draw focus rect
+
+ //SIZE sz;
+ //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
+ //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( ( nType == CTRL_EDITBOX ) || ( nType == CTRL_MULTILINE_EDITBOX ) )
+ {
+ iPart = EP_EDITTEXT;
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = ETS_DISABLED;
+ else if( nState & CTRL_STATE_FOCUSED )
+ iState = ETS_FOCUSED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = ETS_HOT;
+ else
+ iState = ETS_NORMAL;
+
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_LISTBOX )
+ {
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ {
+ iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+
+ if( nType == CTRL_TAB_PANE )
+ {
+ iPart = TABP_PANE;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_FIXEDBORDER )
+ {
+ /*
+ iPart = BP_GROUPBOX;
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = GBS_DISABLED;
+ else
+ iState = GBS_NORMAL;
+ */
+ // The fixed border is only used around the tools->options tabpage where
+ // TABP_PANE fits best
+ iPart = TABP_PANE;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TAB_BODY )
+ {
+ iPart = TABP_BODY;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TAB_ITEM )
+ {
+ iPart = TABP_TABITEMLEFTEDGE;
+ rc.bottom--;
+
+ OSL_ASSERT( aValue.getType() == CTRL_TAB_ITEM );
+
+ const TabitemValue *pValue = static_cast<const TabitemValue*>(&aValue);
+ if( pValue->isBothAligned() )
+ {
+ iPart = TABP_TABITEMLEFTEDGE;
+ rc.right--;
+ }
+ else if( pValue->isLeftAligned() )
+ iPart = TABP_TABITEMLEFTEDGE;
+ else if( pValue->isRightAligned() )
+ iPart = TABP_TABITEMRIGHTEDGE;
+ else iPart = TABP_TABITEM;
+
+ if( !(nState & CTRL_STATE_ENABLED) )
+ iState = TILES_DISABLED;
+ else if( nState & CTRL_STATE_SELECTED )
+ {
+ iState = TILES_SELECTED;
+ // increase the selected tab
+ rc.left-=2;
+ if( pValue && !pValue->isBothAligned() )
+ {
+ if( pValue->isLeftAligned() || pValue->isNotAligned() )
+ rc.right+=2;
+ if( pValue->isRightAligned() )
+ rc.right+=1;
+ }
+ rc.top-=2;
+ rc.bottom+=2;
+ }
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = TILES_HOT;
+ else if( nState & CTRL_STATE_FOCUSED )
+ iState = TILES_FOCUSED; // may need to draw focus rect
+ else
+ iState = TILES_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+
+ if( nType == CTRL_TOOLBAR )
+ {
+ if( nPart == PART_BUTTON )
+ {
+ iPart = TP_BUTTON;
+ sal_Bool bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
+ if( !(nState & CTRL_STATE_ENABLED) )
+ //iState = TS_DISABLED;
+ // disabled buttons are typically not painted at all but we need visual
+ // feedback when travelling by keyboard over disabled entries
+ iState = TS_HOT;
+ else if( nState & CTRL_STATE_PRESSED )
+ iState = TS_PRESSED;
+ else if( nState & CTRL_STATE_ROLLOVER )
+ iState = bChecked ? TS_HOTCHECKED : TS_HOT;
+ else
+ iState = bChecked ? TS_CHECKED : TS_NORMAL;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ // the vertical gripper is not supported in most themes and it makes no
+ // sense to only support horizontal gripper
+ //iPart = (nPart == PART_THUMB_HORZ) ? RP_GRIPPERVERT : RP_GRIPPER;
+ //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ else if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
+ {
+ if( aValue.getType() == CTRL_TOOLBAR )
+ {
+ const ToolbarValue *pValue = static_cast<const ToolbarValue*>(&aValue);
+ if( pValue->mbIsTopDockingArea )
+ rc.top = 0; // extend potential gradient to cover menu bar as well
+ }
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ }
+
+ if( nType == CTRL_MENUBAR )
+ {
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ if( aValue.getType() == CTRL_MENUBAR )
+ {
+ const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
+ rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well
+ }
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( (nState & CTRL_STATE_ENABLED) )
+ iState = (nState & CTRL_STATE_SELECTED) ? MBI_HOT : MBI_NORMAL;
+ else
+ iState = (nState & CTRL_STATE_SELECTED) ? MBI_DISABLEDHOT : MBI_DISABLED;
+ return ImplDrawTheme( hTheme, hDC, MENU_BARITEM, iState, rc, aCaption );
+ }
+ }
+
+ if( nType == CTRL_PROGRESS )
+ {
+ if( nPart != PART_ENTIRE_CONTROL )
+ return FALSE;
+
+ if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
+ return false;
+ RECT aProgressRect = rc;
+ if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
+ return false;
+
+ long nProgressWidth = aValue.getNumericVal();
+ nProgressWidth *= (aProgressRect.right - aProgressRect.left);
+ nProgressWidth /= (rc.right - rc.left);
+ if( Application::GetSettings().GetLayoutRTL() )
+ aProgressRect.left = aProgressRect.right - nProgressWidth;
+ else
+ aProgressRect.right = aProgressRect.left + nProgressWidth;
+
+ return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
+ }
+
+ if( nType == CTRL_SLIDER )
+ {
+ iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_TRACK : TKP_TRACKVERT;
+ iState = (nPart == PART_TRACK_HORZ_AREA) ? TRS_NORMAL : TRVS_NORMAL;
+
+ Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
+ RECT aTRect = rc;
+ if( nPart == PART_TRACK_HORZ_AREA )
+ {
+ long nH = aTrackRect.GetHeight();
+ aTRect.top += (rc.bottom - rc.top - nH)/2;
+ aTRect.bottom = aTRect.top + nH;
+ }
+ else
+ {
+ long nW = aTrackRect.GetWidth();
+ aTRect.left += (rc.right - rc.left - nW)/2;
+ aTRect.right = aTRect.left + nW;
+ }
+ ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );
+
+ RECT aThumbRect;
+ OSL_ASSERT( aValue.getType() == CTRL_SLIDER );
+ const SliderValue* pVal = static_cast<const SliderValue*>(&aValue);
+ aThumbRect.left = pVal->maThumbRect.Left();
+ aThumbRect.top = pVal->maThumbRect.Top();
+ aThumbRect.right = pVal->maThumbRect.Right();
+ aThumbRect.bottom = pVal->maThumbRect.Bottom();
+ iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_THUMB : TKP_THUMBVERT;
+ iState = (nState & CTRL_STATE_ENABLED) ? TUS_NORMAL : TUS_DISABLED;
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
+ }
+
+ if( nType == CTRL_LISTNODE )
+ {
+ if( nPart != PART_ENTIRE_CONTROL )
+ return FALSE;
+
+ ButtonValue aButtonValue = aValue.getTristateVal();
+ iPart = TVP_GLYPH;
+ switch( aButtonValue )
+ {
+ case BUTTONVALUE_ON:
+ iState = GLPS_OPENED;
+ break;
+ case BUTTONVALUE_OFF:
+ iState = GLPS_CLOSED;
+ break;
+ default:
+ return FALSE;
+ }
+ return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
+ }
+
+ if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nType == CTRL_MENU_POPUP )
+ {
+ if( nPart == PART_ENTIRE_CONTROL )
+ {
+ RECT aGutterRC = rc;
+ aGutterRC.left += aValue.getNumericVal();
+ aGutterRC.right = aGutterRC.left+3;
+ return
+ ImplDrawTheme( hTheme, hDC, MENU_POPUPBACKGROUND, 0, rc, aCaption ) &&
+ ImplDrawTheme( hTheme, hDC, MENU_POPUPGUTTER, 0, aGutterRC, aCaption )
+ ;
+ }
+ else if( nPart == PART_MENU_ITEM )
+ {
+ if( (nState & CTRL_STATE_ENABLED) )
+ iState = (nState & CTRL_STATE_SELECTED) ? MPI_HOT : MPI_NORMAL;
+ else
+ iState = (nState & CTRL_STATE_SELECTED) ? MPI_DISABLEDHOT : MPI_DISABLED;
+ return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption );
+ }
+ else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
+ {
+ if( (nState & CTRL_STATE_PRESSED) )
+ {
+ RECT aBGRect = rc;
+ if( aValue.getType() == CTRL_MENU_POPUP )
+ {
+ const MenupopupValue& rMVal( static_cast<const MenupopupValue&>(aValue) );
+ aBGRect.left = rMVal.maItemRect.Left();
+ aBGRect.top = rMVal.maItemRect.Top();
+ aBGRect.bottom = rMVal.maItemRect.Bottom()+1; // see below in drawNativeControl
+ aBGRect.right = rMVal.getNumericVal();
+
+ // FIXME: magic
+ aBGRect.left += 1; aBGRect.top += 1; aBGRect.bottom +=1;
+ }
+ iState = (nState & CTRL_STATE_ENABLED) ? MCB_NORMAL : MCB_DISABLED;
+ ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, aBGRect, aCaption );
+ if( nPart == PART_MENU_ITEM_CHECK_MARK )
+ iState = (nState & CTRL_STATE_ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED;
+ else
+ iState = (nState & CTRL_STATE_ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED;
+ return ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption );
+ }
+ else
+ return true; // unchecked: do nothing
+ }
+ else if( nPart == PART_MENU_SEPARATOR )
+ {
+ rc.left += aValue.getNumericVal(); // adjust for gutter position
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
+ MENU_POPUPSEPARATOR, 0, Rectangle( rc.left, rc.top, rc.right, rc.bottom ) ) );
+ // center the separator inside the passed rectangle
+ long nDY = ((rc.bottom - rc.top + 1) - aRect.GetHeight()) / 2;
+ rc.top += nDY;
+ rc.bottom = rc.top+aRect.GetHeight()-1;
+ return ImplDrawTheme( hTheme, hDC, MENU_POPUPSEPARATOR, 0, rc, aCaption );
+ }
+ }
+ }
+
+ return false;
+}
+
+/*
+ * DrawNativeControl()
+ *
+ * Draws the requested control described by nPart/nState.
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+sal_Bool WinSalGraphics::drawNativeControl( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& aValue,
+ const OUString& aCaption )
+{
+ sal_Bool bOk = false;
+ HTHEME hTheme = NULL;
+
+ switch( nType )
+ {
+ case CTRL_PUSHBUTTON:
+ case CTRL_RADIOBUTTON:
+ case CTRL_CHECKBOX:
+ hTheme = getThemeHandle( mhWnd, L"Button");
+ break;
+ case CTRL_SCROLLBAR:
+ hTheme = getThemeHandle( mhWnd, L"Scrollbar");
+ break;
+ case CTRL_COMBOBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_SPINBOX:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ else
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_SPINBUTTONS:
+ hTheme = getThemeHandle( mhWnd, L"Spin");
+ break;
+ case CTRL_EDITBOX:
+ case CTRL_MULTILINE_EDITBOX:
+ hTheme = getThemeHandle( mhWnd, L"Edit");
+ break;
+ case CTRL_LISTBOX:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
+ hTheme = getThemeHandle( mhWnd, L"Listview");
+ else if( nPart == PART_BUTTON_DOWN )
+ hTheme = getThemeHandle( mhWnd, L"Combobox");
+ break;
+ case CTRL_TAB_PANE:
+ case CTRL_TAB_BODY:
+ case CTRL_TAB_ITEM:
+ case CTRL_FIXEDBORDER:
+ hTheme = getThemeHandle( mhWnd, L"Tab");
+ break;
+ case CTRL_TOOLBAR:
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
+ hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ else
+ // use rebar for grip and background
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ break;
+ case CTRL_MENUBAR:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Rebar");
+ else if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nPart == PART_MENU_ITEM )
+ hTheme = getThemeHandle( mhWnd, L"Menu" );
+ }
+ break;
+ case CTRL_PROGRESS:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"Progress");
+ break;
+ case CTRL_LISTNODE:
+ if( nPart == PART_ENTIRE_CONTROL )
+ hTheme = getThemeHandle( mhWnd, L"TreeView");
+ break;
+ case CTRL_SLIDER:
+ if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
+ hTheme = getThemeHandle( mhWnd, L"Trackbar" );
+ break;
+ case CTRL_MENU_POPUP:
+ if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM ||
+ nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK ||
+ nPart == PART_MENU_SEPARATOR
+ )
+ hTheme = getThemeHandle( mhWnd, L"Menu" );
+ }
+ break;
+ default:
+ hTheme = NULL;
+ break;
+ }
+
+ if( !hTheme )
+ return false;
+
+ Rectangle buttonRect = rControlRegion;
+ RECT rc;
+ rc.left = buttonRect.Left();
+ rc.right = buttonRect.Right()+1;
+ rc.top = buttonRect.Top();
+ rc.bottom = buttonRect.Bottom()+1;
+
+ // set default text alignment
+ int ta = SetTextAlign( mhDC, TA_LEFT|TA_TOP|TA_NOUPDATECP );
+
+ OUString aCaptionStr( aCaption.replace('~', '&') ); // translate mnemonics
+ bOk = ImplDrawNativeControl(mhDC, hTheme, rc,
+ nType, nPart, nState, aValue,
+ aCaptionStr );
+
+ // restore alignment
+ SetTextAlign( mhDC, ta );
+
+
+ //GdiFlush();
+
+ return bOk;
+}
+
+
+/*
+ * DrawNativeControlText()
+ *
+ * OPTIONAL. Draws the requested text for the control described by nPart/nState.
+ * Used if text not drawn by DrawNativeControl().
+ *
+ * rControlRegion: The bounding region of the complete control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+sal_Bool WinSalGraphics::drawNativeControlText( ControlType,
+ ControlPart,
+ const Rectangle&,
+ ControlState,
+ const ImplControlValue&,
+ const OUString& )
+{
+ return( false );
+}
+
+
+/*
+ * GetNativeControlRegion()
+ *
+ * If the return value is TRUE, rNativeBoundingRegion
+ * contains the true bounding region covered by the control
+ * including any adornment, while rNativeContentRegion contains the area
+ * within the control that can be safely drawn into without drawing over
+ * the borders of the control.
+ *
+ * rControlRegion: The bounding region of the control in VCL frame coordinates.
+ * aValue: An optional value (tristate/numerical/string)
+ * aCaption: A caption or title string (like button text etc)
+ */
+sal_Bool WinSalGraphics::getNativeControlRegion( ControlType nType,
+ ControlPart nPart,
+ const Rectangle& rControlRegion,
+ ControlState nState,
+ const ImplControlValue& rControlValue,
+ const OUString&,
+ Rectangle &rNativeBoundingRegion,
+ Rectangle &rNativeContentRegion )
+{
+ sal_Bool bRet = FALSE;
+
+ HDC hDC = GetDC( mhWnd );
+ if( nType == CTRL_TOOLBAR )
+ {
+ if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
+ {
+ /*
+ // the vertical gripper is not supported in most themes and it makes no
+ // sense to only support horizontal gripper
+
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == PART_THUMB_HORZ ? RP_GRIPPERVERT : RP_GRIPPER,
+ 0, rControlRegion.GetBoundRect() ) );
+ if( nPart == PART_THUMB_HORZ && !aRect.IsEmpty() )
+ {
+ Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
+ rNativeContentRegion = aVertRect;
+ }
+ else
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ */
+ }
+ if( nPart == PART_BUTTON )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN,
+ TS_HOT, rControlRegion ) );
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+ }
+ if( nType == CTRL_PROGRESS && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Progress");
+ if( hTheme )
+ {
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR,
+ 0, rControlRegion ) );
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !rNativeContentRegion.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+ if( (nType == CTRL_LISTBOX || nType == CTRL_COMBOBOX ) && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox");
+ if( hTheme )
+ {
+ Rectangle aBoxRect( rControlRegion );
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON,
+ CBXS_NORMAL, aBoxRect ) );
+ if( aRect.GetHeight() > aBoxRect.GetHeight() )
+ aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
+ if( aRect.GetWidth() > aBoxRect.GetWidth() )
+ aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
+ rNativeContentRegion = aBoxRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ if( !aRect.IsEmpty() )
+ bRet = TRUE;
+ }
+ }
+
+ if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Edit");
+ if( hTheme )
+ {
+ // get border size
+ Rectangle aBoxRect( rControlRegion );
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER,
+ EBWBS_HOT, aBoxRect ) );
+ // ad app font height
+ NONCLIENTMETRICSW aNonClientMetrics;
+ aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
+ if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
+ {
+ long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight;
+ if( nFontHeight < 0 )
+ nFontHeight = -nFontHeight;
+
+ if( aRect.GetHeight() && nFontHeight )
+ {
+ aRect.Bottom() += aRect.GetHeight();
+ aRect.Bottom() += nFontHeight;
+ if( aRect.GetHeight() > aBoxRect.GetHeight() )
+ aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
+ if( aRect.GetWidth() > aBoxRect.GetWidth() )
+ aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
+ rNativeContentRegion = aBoxRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ if( GetSalData()->mbThemeMenuSupport )
+ {
+ if( nType == CTRL_MENU_POPUP )
+ {
+ if( nPart == PART_MENU_ITEM_CHECK_MARK ||
+ nPart == PART_MENU_ITEM_RADIO_MARK )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Menu");
+ Rectangle aBoxRect( rControlRegion );
+ Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
+ MENU_POPUPCHECK,
+ MC_CHECKMARKNORMAL,
+ aBoxRect ) );
+ if( aBoxRect.GetWidth() && aBoxRect.GetHeight() )
+ {
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+
+ if( nType == CTRL_SLIDER && ( (nPart == PART_THUMB_HORZ) || (nPart == PART_THUMB_VERT) ) )
+ {
+ HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar");
+ if( hTheme )
+ {
+ int iPart = (nPart == PART_THUMB_HORZ) ? TKP_THUMB : TKP_THUMBVERT;
+ int iState = (nPart == PART_THUMB_HORZ) ? TUS_NORMAL : TUVS_NORMAL;
+ Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
+ if( nPart == PART_THUMB_HORZ )
+ {
+ long nW = aThumbRect.GetWidth();
+ Rectangle aRect( rControlRegion );
+ aRect.Right() = aRect.Left() + nW - 1;
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ }
+ else
+ {
+ long nH = aThumbRect.GetHeight();
+ Rectangle aRect( rControlRegion );
+ aRect.Bottom() = aRect.Top() + nH - 1;
+ rNativeContentRegion = aRect;
+ rNativeBoundingRegion = rNativeContentRegion;
+ }
+ bRet = TRUE;
+ }
+ }
+
+ if ( ( nType == CTRL_TAB_ITEM ) && ( nPart == PART_ENTIRE_CONTROL ) )
+ {
+ Rectangle aControlRect( rControlRegion );
+ rNativeContentRegion = aControlRect;
+
+ --aControlRect.Bottom();
+
+ if( rControlValue.getType() == CTRL_TAB_ITEM )
+ {
+ const TabitemValue *pValue = static_cast<const TabitemValue*>(&rControlValue);
+ if ( pValue->isBothAligned() )
+ --aControlRect.Right();
+
+ if ( nState & CTRL_STATE_SELECTED )
+ {
+ aControlRect.Left() -= 2;
+ if ( pValue && !pValue->isBothAligned() )
+ {
+ if ( pValue->isLeftAligned() || pValue->isNotAligned() )
+ aControlRect.Right() += 2;
+ if ( pValue->isRightAligned() )
+ aControlRect.Right() += 1;
+ }
+ aControlRect.Top() -= 2;
+ aControlRect.Bottom() += 2;
+ }
+ }
+ rNativeBoundingRegion = aControlRect;
+ bRet = TRUE;
+ }
+
+ ReleaseDC( mhWnd, hDC );
+ return( bRet );
+}
+
diff --git a/vcl/win/source/gdi/salprn.cxx b/vcl/win/source/gdi/salprn.cxx
new file mode 100644
index 000000000000..263d06670584
--- /dev/null
+++ b/vcl/win/source/gdi/salprn.cxx
@@ -0,0 +1,2372 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+
+#include <osl/module.h>
+
+#include <tools/urlobj.hxx>
+#include <tools/svwin.h>
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salgdi.h>
+#include <win/salframe.h>
+#include <win/salprn.h>
+
+#include <salptype.hxx>
+#include <print.h>
+#include <jobset.h>
+
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/XFilePicker.hpp>
+#include <com/sun/star/ui/dialogs/XFilterManager.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <malloc.h>
+
+#ifdef __MINGW32__
+#define CATCH_DRIVER_EX_BEGIN \
+ jmp_buf jmpbuf; \
+ __SEHandler han; \
+ if (__builtin_setjmp(jmpbuf) == 0) \
+ { \
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER)
+
+#define CATCH_DRIVER_EX_END(mes, p) \
+ } \
+ han.Reset()
+#define CATCH_DRIVER_EX_END_2(mes) \
+ } \
+ han.Reset()
+#else
+#define CATCH_DRIVER_EX_BEGIN \
+ __try \
+ {
+#define CATCH_DRIVER_EX_END(mes, p) \
+ } \
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
+ { \
+ DBG_ERROR( mes ); \
+ p->markInvalid(); \
+ }
+#define CATCH_DRIVER_EX_END_2(mes) \
+ } \
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))\
+ { \
+ DBG_ERROR( mes ); \
+ }
+#endif
+
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ui::dialogs;
+using namespace rtl;
+
+// =======================================================================
+
+static char aImplWindows[] = "windows";
+static char aImplDevices[] = "devices";
+static char aImplDevice[] = "device";
+
+static LPDEVMODEA SAL_DEVMODE_A( const ImplJobSetup* pSetupData )
+{
+ LPDEVMODEA pRet = NULL;
+ SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
+ if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_A &&
+ pSetupData->mnDriverDataLen >= sizeof(DEVMODEA)+sizeof(SalDriverData)-1
+ )
+ pRet = ((LPDEVMODEA)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
+ return pRet;
+}
+
+static LPDEVMODEW SAL_DEVMODE_W( const ImplJobSetup* pSetupData )
+{
+ LPDEVMODEW pRet = NULL;
+ SalDriverData* pDrv = (SalDriverData*)pSetupData->mpDriverData;
+ if( pDrv->mnVersion == SAL_DRIVERDATA_VERSION_W &&
+ pSetupData->mnDriverDataLen >= sizeof(DEVMODEW)+sizeof(SalDriverData)-1
+ )
+ pRet = ((LPDEVMODEW)((pSetupData->mpDriverData) + (pDrv->mnDriverOffset)));
+ return pRet;
+}
+
+// =======================================================================
+
+static sal_uLong ImplWinQueueStatusToSal( DWORD nWinStatus )
+{
+ sal_uLong nStatus = 0;
+ if ( nWinStatus & PRINTER_STATUS_PAUSED )
+ nStatus |= QUEUE_STATUS_PAUSED;
+ if ( nWinStatus & PRINTER_STATUS_ERROR )
+ nStatus |= QUEUE_STATUS_ERROR;
+ if ( nWinStatus & PRINTER_STATUS_PENDING_DELETION )
+ nStatus |= QUEUE_STATUS_PENDING_DELETION;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_JAM )
+ nStatus |= QUEUE_STATUS_PAPER_JAM;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_OUT )
+ nStatus |= QUEUE_STATUS_PAPER_OUT;
+ if ( nWinStatus & PRINTER_STATUS_MANUAL_FEED )
+ nStatus |= QUEUE_STATUS_MANUAL_FEED;
+ if ( nWinStatus & PRINTER_STATUS_PAPER_PROBLEM )
+ nStatus |= QUEUE_STATUS_PAPER_PROBLEM;
+ if ( nWinStatus & PRINTER_STATUS_OFFLINE )
+ nStatus |= QUEUE_STATUS_OFFLINE;
+ if ( nWinStatus & PRINTER_STATUS_IO_ACTIVE )
+ nStatus |= QUEUE_STATUS_IO_ACTIVE;
+ if ( nWinStatus & PRINTER_STATUS_BUSY )
+ nStatus |= QUEUE_STATUS_BUSY;
+ if ( nWinStatus & PRINTER_STATUS_PRINTING )
+ nStatus |= QUEUE_STATUS_PRINTING;
+ if ( nWinStatus & PRINTER_STATUS_OUTPUT_BIN_FULL )
+ nStatus |= QUEUE_STATUS_OUTPUT_BIN_FULL;
+ if ( nWinStatus & PRINTER_STATUS_WAITING )
+ nStatus |= QUEUE_STATUS_WAITING;
+ if ( nWinStatus & PRINTER_STATUS_PROCESSING )
+ nStatus |= QUEUE_STATUS_PROCESSING;
+ if ( nWinStatus & PRINTER_STATUS_INITIALIZING )
+ nStatus |= QUEUE_STATUS_INITIALIZING;
+ if ( nWinStatus & PRINTER_STATUS_WARMING_UP )
+ nStatus |= QUEUE_STATUS_WARMING_UP;
+ if ( nWinStatus & PRINTER_STATUS_TONER_LOW )
+ nStatus |= QUEUE_STATUS_TONER_LOW;
+ if ( nWinStatus & PRINTER_STATUS_NO_TONER )
+ nStatus |= QUEUE_STATUS_NO_TONER;
+ if ( nWinStatus & PRINTER_STATUS_PAGE_PUNT )
+ nStatus |= QUEUE_STATUS_PAGE_PUNT;
+ if ( nWinStatus & PRINTER_STATUS_USER_INTERVENTION )
+ nStatus |= QUEUE_STATUS_USER_INTERVENTION;
+ if ( nWinStatus & PRINTER_STATUS_OUT_OF_MEMORY )
+ nStatus |= QUEUE_STATUS_OUT_OF_MEMORY;
+ if ( nWinStatus & PRINTER_STATUS_DOOR_OPEN )
+ nStatus |= QUEUE_STATUS_DOOR_OPEN;
+ if ( nWinStatus & PRINTER_STATUS_SERVER_UNKNOWN )
+ nStatus |= QUEUE_STATUS_SERVER_UNKNOWN;
+ if ( nWinStatus & PRINTER_STATUS_POWER_SAVE )
+ nStatus |= QUEUE_STATUS_POWER_SAVE;
+ if ( !nStatus && !(nWinStatus & PRINTER_STATUS_NOT_AVAILABLE) )
+ nStatus |= QUEUE_STATUS_READY;
+ return nStatus;
+}
+
+// -----------------------------------------------------------------------
+
+static void getPrinterQueueInfoOldStyle( ImplPrnQueueList* pList )
+{
+ DWORD i;
+ DWORD n;
+ DWORD nBytes = 0;
+ DWORD nInfoPrn2;
+ sal_Bool bFound = FALSE;
+ PRINTER_INFO_2* pWinInfo2 = NULL;
+ PRINTER_INFO_2* pGetInfo2;
+ EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoPrn2 );
+ if ( nBytes )
+ {
+ pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoPrn2 ) )
+ {
+ pGetInfo2 = pWinInfo2;
+ for ( i = 0; i < nInfoPrn2; i++ )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = ImplSalGetUniString( pGetInfo2->pPrinterName );
+ pInfo->maDriver = ImplSalGetUniString( pGetInfo2->pDriverName );
+ XubString aPortName;
+ if ( pGetInfo2->pPortName )
+ aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
+ pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pComment )
+ pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pGetInfo2->Status );
+ pInfo->mnJobs = pGetInfo2->cJobs;
+ pInfo->mpSysData = new XubString( aPortName );
+ pList->Add( pInfo );
+ pGetInfo2++;
+ }
+
+ bFound = TRUE;
+ }
+ }
+
+ // read printers from win.ini
+ // TODO: MSDN: GetProfileString() should not be called from server
+ // code because it is just there for WIN16 compatibility
+ UINT nSize = 4096;
+ char* pBuf = new char[nSize];
+ UINT nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
+ while ( nRead >= nSize-2 )
+ {
+ nSize += 2048;
+ delete []pBuf;
+ pBuf = new char[nSize];
+ nRead = GetProfileStringA( aImplDevices, NULL, "", pBuf, nSize );
+ }
+
+ // extract printer names from buffer and fill list
+ char* pName = pBuf;
+ while ( *pName )
+ {
+ char* pPortName;
+ char* pTmp;
+ char aPortBuf[256];
+ GetProfileStringA( aImplDevices, pName, "", aPortBuf, sizeof( aPortBuf ) );
+
+ pPortName = aPortBuf;
+
+ // create name
+ xub_StrLen nNameLen = sal::static_int_cast<xub_StrLen>(strlen( pName ));
+ XubString aName( ImplSalGetUniString( pName, nNameLen ) );
+
+ // get driver name
+ pTmp = pPortName;
+ while ( *pTmp != ',' )
+ pTmp++;
+ XubString aDriver( ImplSalGetUniString( pPortName, (sal_uInt16)(pTmp-pPortName) ) );
+ pPortName = pTmp;
+
+ // get port names
+ do
+ {
+ pPortName++;
+ pTmp = pPortName;
+ while ( *pTmp && (*pTmp != ',') )
+ pTmp++;
+
+ String aPortName( ImplSalGetUniString( pPortName, (sal_uInt16)(pTmp-pPortName) ) );
+
+ // create new entry
+ // look up if printer was already found in first loop
+ sal_Bool bAdd = TRUE;
+ if ( pWinInfo2 )
+ {
+ pGetInfo2 = pWinInfo2;
+ for ( n = 0; n < nInfoPrn2; n++ )
+ {
+ if ( aName.EqualsIgnoreCaseAscii( pGetInfo2->pPrinterName ) )
+ {
+ bAdd = FALSE;
+ break;
+ }
+ pGetInfo2++;
+ }
+ }
+ // if it's a new printer, add it
+ if ( bAdd )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = aName;
+ pInfo->maDriver = aDriver;
+ pInfo->maLocation = aPortName;
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = QUEUE_JOBS_DONTKNOW;
+ pInfo->mpSysData = new XubString( aPortName );
+ pList->Add( pInfo );
+ }
+ }
+ while ( *pTmp == ',' );
+
+ pName += nNameLen + 1;
+ }
+
+ delete []pBuf;
+ rtl_freeMemory( pWinInfo2 );
+}
+
+void WinSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
+{
+ if( ! aSalShlData.mbWPrinter )
+ {
+ getPrinterQueueInfoOldStyle( pList );
+ return;
+ }
+ DWORD i;
+ DWORD nBytes = 0;
+ DWORD nInfoPrn4 = 0;
+ PRINTER_INFO_4W* pWinInfo4 = NULL;
+ EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, NULL, 0, &nBytes, &nInfoPrn4 );
+ if ( nBytes )
+ {
+ pWinInfo4 = (PRINTER_INFO_4W*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersW( PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS, NULL, 4, (LPBYTE)pWinInfo4, nBytes, &nBytes, &nInfoPrn4 ) )
+ {
+ for ( i = 0; i < nInfoPrn4; i++ )
+ {
+ SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
+ pInfo->maPrinterName = UniString( reinterpret_cast< const sal_Unicode* >(pWinInfo4[i].pPrinterName) );
+ pInfo->mnStatus = 0;
+ pInfo->mnJobs = 0;
+ pInfo->mpSysData = NULL;
+ pList->Add( pInfo );
+ }
+ }
+ rtl_freeMemory( pWinInfo4 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void getPrinterQueueStateOldStyle( SalPrinterQueueInfo* pInfo )
+{
+ DWORD nBytes = 0;
+ DWORD nInfoRet;
+ PRINTER_INFO_2* pWinInfo2;
+ EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &nBytes, &nInfoRet );
+ if ( nBytes )
+ {
+ pWinInfo2 = (PRINTER_INFO_2*) rtl_allocateMemory( nBytes );
+ if ( EnumPrintersA( PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes, &nInfoRet ) )
+ {
+ PRINTER_INFO_2* pGetInfo2 = pWinInfo2;
+ for ( DWORD i = 0; i < nInfoRet; i++ )
+ {
+ if ( pInfo->maPrinterName.EqualsAscii( pGetInfo2->pPrinterName ) &&
+ ( pInfo->maDriver.Len() == 0 ||
+ pInfo->maDriver.EqualsAscii( pGetInfo2->pDriverName ) )
+ )
+ {
+ XubString aPortName;
+ if ( pGetInfo2->pPortName )
+ aPortName = ImplSalGetUniString( pGetInfo2->pPortName );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pLocation && strlen( pGetInfo2->pLocation ) )
+ pInfo->maLocation = ImplSalGetUniString( pGetInfo2->pLocation );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pGetInfo2->pComment )
+ pInfo->maComment = ImplSalGetUniString( pGetInfo2->pComment );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pGetInfo2->Status );
+ pInfo->mnJobs = pGetInfo2->cJobs;
+ if( ! pInfo->mpSysData )
+ pInfo->mpSysData = new XubString( aPortName );
+ break;
+ }
+
+ pGetInfo2++;
+ }
+ }
+
+ rtl_freeMemory( pWinInfo2 );
+ }
+}
+
+void WinSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
+{
+ if( ! aSalShlData.mbWPrinter )
+ {
+ getPrinterQueueStateOldStyle( pInfo );
+ return;
+ }
+
+ HANDLE hPrinter = 0;
+ LPWSTR pPrnName = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pInfo->maPrinterName.GetBuffer()));
+ if( OpenPrinterW( pPrnName, &hPrinter, NULL ) )
+ {
+ DWORD nBytes = 0;
+ GetPrinterW( hPrinter, 2, NULL, 0, &nBytes );
+ if( nBytes )
+ {
+ PRINTER_INFO_2W* pWinInfo2 = (PRINTER_INFO_2W*)rtl_allocateMemory(nBytes);
+ if( GetPrinterW( hPrinter, 2, (LPBYTE)pWinInfo2, nBytes, &nBytes ) )
+ {
+ if( pWinInfo2->pDriverName )
+ pInfo->maDriver = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pDriverName) );
+ XubString aPortName;
+ if ( pWinInfo2->pPortName )
+ aPortName = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pPortName) );
+ // pLocation can be 0 (the Windows docu doesn't describe this)
+ if ( pWinInfo2->pLocation && *pWinInfo2->pLocation )
+ pInfo->maLocation = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pLocation) );
+ else
+ pInfo->maLocation = aPortName;
+ // pComment can be 0 (the Windows docu doesn't describe this)
+ if ( pWinInfo2->pComment )
+ pInfo->maComment = String( reinterpret_cast< const sal_Unicode* >(pWinInfo2->pComment) );
+ pInfo->mnStatus = ImplWinQueueStatusToSal( pWinInfo2->Status );
+ pInfo->mnJobs = pWinInfo2->cJobs;
+ if( ! pInfo->mpSysData )
+ pInfo->mpSysData = new XubString( aPortName );
+ }
+ rtl_freeMemory(pWinInfo2);
+ }
+ ClosePrinter( hPrinter );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
+{
+ delete (String*)(pInfo->mpSysData);
+ delete pInfo;
+}
+
+// -----------------------------------------------------------------------
+XubString WinSalInstance::GetDefaultPrinter()
+{
+ static bool bGetDefPrtAPI = true;
+ static sal_Bool(WINAPI*pGetDefaultPrinter)(LPWSTR,LPDWORD) = NULL;
+ // try to use GetDefaultPrinter API (not available prior to W2000)
+ if( bGetDefPrtAPI )
+ {
+ bGetDefPrtAPI = false;
+ // check for W2k and XP
+ if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ {
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "winspool.drv" ) );
+ oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ oslGenericFunction pFunc = NULL;
+ if( pLib )
+ {
+ OUString queryFuncName( RTL_CONSTASCII_USTRINGPARAM( "GetDefaultPrinterW" ) );
+ pFunc = osl_getFunctionSymbol( pLib, queryFuncName.pData );
+ }
+
+ pGetDefaultPrinter = (sal_Bool(WINAPI*)(LPWSTR,LPDWORD)) pFunc;
+ }
+ }
+ if( pGetDefaultPrinter )
+ {
+ DWORD nChars = 0;
+ pGetDefaultPrinter( NULL, &nChars );
+ if( nChars )
+ {
+ LPWSTR pStr = (LPWSTR)rtl_allocateMemory(nChars*sizeof(WCHAR));
+ XubString aDefPrt;
+ if( pGetDefaultPrinter( pStr, &nChars ) )
+ {
+ aDefPrt = reinterpret_cast<sal_Unicode* >(pStr);
+ }
+ rtl_freeMemory( pStr );
+ if( aDefPrt.Len() )
+ return aDefPrt;
+ }
+ }
+
+ // get default printer from win.ini
+ char szBuffer[256];
+ GetProfileStringA( aImplWindows, aImplDevice, "", szBuffer, sizeof( szBuffer ) );
+ if ( szBuffer[0] )
+ {
+ // Printername suchen
+ char* pBuf = szBuffer;
+ char* pTmp = pBuf;
+ while ( *pTmp && (*pTmp != ',') )
+ pTmp++;
+ return ImplSalGetUniString( pBuf, (xub_StrLen)(pTmp-pBuf) );
+ }
+ else
+ return XubString();
+}
+
+// =======================================================================
+
+static DWORD ImplDeviceCaps( WinSalInfoPrinter* pPrinter, WORD nCaps,
+ BYTE* pOutput, const ImplJobSetup* pSetupData )
+{
+ if( aSalShlData.mbWPrinter )
+ {
+ DEVMODEW* pDevMode;
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ pDevMode = NULL;
+ else
+ pDevMode = SAL_DEVMODE_W( pSetupData );
+
+ return DeviceCapabilitiesW( reinterpret_cast<LPCWSTR>(pPrinter->maDeviceName.GetBuffer()),
+ reinterpret_cast<LPCWSTR>(pPrinter->maPortName.GetBuffer()),
+ nCaps, (LPWSTR)pOutput, pDevMode );
+ }
+ else
+ {
+ DEVMODEA* pDevMode;
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ pDevMode = NULL;
+ else
+ pDevMode = SAL_DEVMODE_A( pSetupData );
+
+ return DeviceCapabilitiesA( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ ImplSalGetWinAnsiString( pPrinter->maPortName, TRUE ).GetBuffer(),
+ nCaps, (LPSTR)pOutput, pDevMode );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter,
+ ImplJobSetup* pSetupData, sal_Bool bDelete )
+{
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ // signature and size must fit to avoid using
+ // JobSetups from a wrong system
+
+ // initialize versions from jobsetup
+ // those will be overwritten with driver's version
+ DEVMODEA* pDevModeA = NULL;
+ DEVMODEW* pDevModeW = NULL;
+ LONG dmSpecVersion = -1;
+ LONG dmDriverVersion = -1;
+ SalDriverData* pSalDriverData = (SalDriverData*)pSetupData->mpDriverData;
+ BYTE* pDriverData = ((BYTE*)pSalDriverData) + pSalDriverData->mnDriverOffset;
+ if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_W )
+ {
+ if( aSalShlData.mbWPrinter )
+ pDevModeW = (DEVMODEW*)pDriverData;
+ }
+ else if( pSalDriverData->mnVersion == SAL_DRIVERDATA_VERSION_A )
+ {
+ if( ! aSalShlData.mbWPrinter )
+ pDevModeA = (DEVMODEA*)pDriverData;
+ }
+
+ long nSysJobSize = -1;
+ if( pPrinter && ( pDevModeA || pDevModeW ) )
+ {
+ // just too many driver crashes in that area -> check the dmSpecVersion and dmDriverVersion fields always !!!
+ // this prevents using the jobsetup between different Windows versions (eg from XP to 9x) but we
+ // can avoid potential driver crashes as their jobsetups are often not compatible
+ // #110800#, #111151#, #112381#, #i16580#, #i14173# and perhaps #112375#
+ ByteString aPrinterNameA= ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
+ HANDLE hPrn;
+ LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
+ if ( ! aSalShlData.mbWPrinter )
+ {
+ if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
+ return FALSE;
+ }
+ else
+ if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
+ return FALSE;
+
+ // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
+ if( hPrn == HGDI_ERROR )
+ return FALSE;
+
+ if( aSalShlData.mbWPrinter )
+ {
+ nSysJobSize = DocumentPropertiesW( 0, hPrn,
+ pPrinterNameW,
+ NULL, NULL, 0 );
+ }
+ else
+ {
+ nSysJobSize = DocumentPropertiesA( 0, hPrn,
+ (LPSTR)aPrinterNameA.GetBuffer(),
+ NULL, NULL, 0 );
+ }
+
+ if( nSysJobSize < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+ BYTE *pBuffer = (BYTE*)_alloca( nSysJobSize );
+ LONG nRet = -1;
+ if( aSalShlData.mbWPrinter )
+ {
+ nRet = DocumentPropertiesW( 0, hPrn,
+ pPrinterNameW,
+ (LPDEVMODEW)pBuffer, NULL, DM_OUT_BUFFER );
+ }
+ else
+ {
+ nRet = DocumentPropertiesA( 0, hPrn,
+ (LPSTR)aPrinterNameA.GetBuffer(),
+ (LPDEVMODEA)pBuffer, NULL, DM_OUT_BUFFER );
+ }
+ if( nRet < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+
+ // the spec version differs between the windows platforms, ie 98,NT,2000/XP
+ // this allows us to throw away printer settings from other platforms that might crash a buggy driver
+ // we check the driver version as well
+ dmSpecVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmSpecVersion : ((DEVMODEA*)pBuffer)->dmSpecVersion;
+ dmDriverVersion = aSalShlData.mbWPrinter ? ((DEVMODEW*)pBuffer)->dmDriverVersion : ((DEVMODEA*)pBuffer)->dmDriverVersion;
+
+ ClosePrinter( hPrn );
+ }
+ SalDriverData* pSetupDriverData = (SalDriverData*)(pSetupData->mpDriverData);
+ if ( (pSetupData->mnSystem == JOBSETUP_SYSTEM_WINDOWS) &&
+ (pPrinter->maDriverName == pSetupData->maDriver) &&
+ (pSetupData->mnDriverDataLen > sizeof( SalDriverData )) &&
+ (long)(pSetupData->mnDriverDataLen - pSetupDriverData->mnDriverOffset) == nSysJobSize &&
+ pSetupDriverData->mnSysSignature == SAL_DRIVERDATA_SYSSIGN )
+ {
+ if( pDevModeA &&
+ (dmSpecVersion == pDevModeA->dmSpecVersion) &&
+ (dmDriverVersion == pDevModeA->dmDriverVersion) )
+ return TRUE;
+ if( pDevModeW &&
+ (dmSpecVersion == pDevModeW->dmSpecVersion) &&
+ (dmDriverVersion == pDevModeW->dmDriverVersion) )
+ return TRUE;
+ }
+ if ( bDelete )
+ {
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mpDriverData = NULL;
+ pSetupData->mnDriverDataLen = 0;
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData,
+ sal_Bool bIn, WinSalFrame* pVisibleDlgParent )
+{
+ ByteString aPrinterNameA = ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE );
+ HANDLE hPrn;
+ LPWSTR pPrinterNameW = reinterpret_cast<LPWSTR>(const_cast<sal_Unicode*>(pPrinter->maDeviceName.GetBuffer()));
+ if( aSalShlData.mbWPrinter )
+ {
+ if ( !OpenPrinterW( pPrinterNameW, &hPrn, NULL ) )
+ return FALSE;
+ }
+ else
+ {
+ if ( !OpenPrinterA( (LPSTR)aPrinterNameA.GetBuffer(), &hPrn, NULL ) )
+ return FALSE;
+ }
+ // #131642# hPrn==HGDI_ERROR even though OpenPrinter() succeeded!
+ if( hPrn == HGDI_ERROR )
+ return FALSE;
+
+ LONG nRet;
+ LONG nSysJobSize = -1;
+ HWND hWnd = 0;
+ DWORD nMode = DM_OUT_BUFFER;
+ sal_uLong nDriverDataLen = 0;
+ SalDriverData* pOutBuffer = NULL;
+ BYTE* pInBuffer = NULL;
+
+ if( aSalShlData.mbWPrinter )
+ {
+ nSysJobSize = DocumentPropertiesW( hWnd, hPrn,
+ pPrinterNameW,
+ NULL, NULL, 0 );
+ }
+ else
+ nSysJobSize = DocumentPropertiesA( hWnd, hPrn,
+ (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ NULL, NULL, 0 );
+ if ( nSysJobSize < 0 )
+ {
+ ClosePrinter( hPrn );
+ return FALSE;
+ }
+
+ // Outputbuffer anlegen
+ nDriverDataLen = sizeof(SalDriverData) + nSysJobSize-1;
+ pOutBuffer = (SalDriverData*)rtl_allocateZeroMemory( nDriverDataLen );
+ pOutBuffer->mnSysSignature = SAL_DRIVERDATA_SYSSIGN;
+ pOutBuffer->mnVersion = aSalShlData.mbWPrinter ? SAL_DRIVERDATA_VERSION_W : SAL_DRIVERDATA_VERSION_A;
+ // calculate driver data offset including structure padding
+ pOutBuffer->mnDriverOffset = sal::static_int_cast<sal_uInt16>(
+ (char*)pOutBuffer->maDriverData -
+ (char*)pOutBuffer );
+
+ // Testen, ob wir einen geeigneten Inputbuffer haben
+ if ( bIn && ImplTestSalJobSetup( pPrinter, pSetupData, FALSE ) )
+ {
+ pInBuffer = (BYTE*)pSetupData->mpDriverData + ((SalDriverData*)pSetupData->mpDriverData)->mnDriverOffset;
+ nMode |= DM_IN_BUFFER;
+ }
+
+ // Testen, ob Dialog angezeigt werden soll
+ if ( pVisibleDlgParent )
+ {
+ hWnd = pVisibleDlgParent->mhWnd;
+ nMode |= DM_IN_PROMPT;
+ }
+
+ // Release mutex, in the other case we don't get paints and so on
+ sal_uLong nMutexCount=0;
+ if ( pVisibleDlgParent )
+ nMutexCount = ImplSalReleaseYieldMutex();
+
+ BYTE* pOutDevMode = (((BYTE*)pOutBuffer) + pOutBuffer->mnDriverOffset);
+ if( aSalShlData.mbWPrinter )
+ {
+ nRet = DocumentPropertiesW( hWnd, hPrn,
+ pPrinterNameW,
+ (LPDEVMODEW)pOutDevMode, (LPDEVMODEW)pInBuffer, nMode );
+ }
+ else
+ {
+ nRet = DocumentPropertiesA( hWnd, hPrn,
+ (LPSTR)ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ).GetBuffer(),
+ (LPDEVMODEA)pOutDevMode, (LPDEVMODEA)pInBuffer, nMode );
+ }
+ if ( pVisibleDlgParent )
+ ImplSalAcquireYieldMutex( nMutexCount );
+ ClosePrinter( hPrn );
+
+ if( (nRet < 0) || (pVisibleDlgParent && (nRet == IDCANCEL)) )
+ {
+ rtl_freeMemory( pOutBuffer );
+ return FALSE;
+ }
+
+ // fill up string buffers with 0 so they do not influence a JobSetup's memcmp
+ if( aSalShlData.mbWPrinter )
+ {
+ if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 64 )
+ {
+ sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmDeviceName );
+ if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )/sizeof(sal_Unicode) )
+ memset( ((LPDEVMODEW)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmDeviceName )-(nLen*sizeof(sal_Unicode)) );
+ }
+ if( ((LPDEVMODEW)pOutDevMode)->dmSize >= 166 )
+ {
+ sal_Int32 nLen = rtl_ustr_getLength( (const sal_Unicode*)((LPDEVMODEW)pOutDevMode)->dmFormName );
+ if ( nLen < sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )/sizeof(sal_Unicode) )
+ memset( ((LPDEVMODEW)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEW)pOutDevMode)->dmFormName )-(nLen*sizeof(sal_Unicode)) );
+ }
+ }
+ else
+ {
+ if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 32 )
+ {
+ sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmDeviceName );
+ if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName ) )
+ memset( ((LPDEVMODEA)pOutDevMode)->dmDeviceName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmDeviceName )-nLen );
+ }
+ if( ((LPDEVMODEA)pOutDevMode)->dmSize >= 102 )
+ {
+ sal_Int32 nLen = strlen( (const char*)((LPDEVMODEA)pOutDevMode)->dmFormName );
+ if ( nLen < sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName ) )
+ memset( ((LPDEVMODEA)pOutDevMode)->dmFormName+nLen, 0, sizeof( ((LPDEVMODEA)pOutDevMode)->dmFormName )-nLen );
+ }
+ }
+
+ // update data
+ if ( pSetupData->mpDriverData )
+ rtl_freeMemory( pSetupData->mpDriverData );
+ pSetupData->mnDriverDataLen = nDriverDataLen;
+ pSetupData->mpDriverData = (BYTE*)pOutBuffer;
+ pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+#define DECLARE_DEVMODE( i )\
+ DEVMODEA* pDevModeA = SAL_DEVMODE_A(i);\
+ DEVMODEW* pDevModeW = SAL_DEVMODE_W(i);\
+ if( pDevModeA == NULL && pDevModeW == NULL )\
+ return
+
+#define CHOOSE_DEVMODE(i)\
+ (pDevModeW ? pDevModeW->i : pDevModeA->i)
+
+static void ImplDevModeToJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
+{
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ return;
+
+ DECLARE_DEVMODE( pSetupData );
+
+ // Orientation
+ if ( nFlags & SAL_JOBSET_ORIENTATION )
+ {
+ if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_PORTRAIT )
+ pSetupData->meOrientation = ORIENTATION_PORTRAIT;
+ else if ( CHOOSE_DEVMODE(dmOrientation) == DMORIENT_LANDSCAPE )
+ pSetupData->meOrientation = ORIENTATION_LANDSCAPE;
+ }
+
+ // PaperBin
+ if ( nFlags & SAL_JOBSET_PAPERBIN )
+ {
+ sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
+
+ if ( nCount && (nCount != GDI_ERROR) )
+ {
+ WORD* pBins = (WORD*)rtl_allocateZeroMemory( nCount*sizeof(WORD) );
+ ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
+ pSetupData->mnPaperBin = 0;
+
+ // search the right bin and assign index to mnPaperBin
+ for( sal_uLong i = 0; i < nCount; i++ )
+ {
+ if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] )
+ {
+ pSetupData->mnPaperBin = (sal_uInt16)i;
+ break;
+ }
+ }
+
+ rtl_freeMemory( pBins );
+ }
+ }
+
+ // PaperSize
+ if ( nFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ if( (CHOOSE_DEVMODE(dmFields) & (DM_PAPERWIDTH|DM_PAPERLENGTH)) == (DM_PAPERWIDTH|DM_PAPERLENGTH) )
+ {
+ pSetupData->mnPaperWidth = CHOOSE_DEVMODE(dmPaperWidth)*10;
+ pSetupData->mnPaperHeight = CHOOSE_DEVMODE(dmPaperLength)*10;
+ }
+ else
+ {
+ sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
+ WORD* pPapers = NULL;
+ sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
+ POINT* pPaperSizes = NULL;
+ if ( nPaperCount && (nPaperCount != GDI_ERROR) )
+ {
+ pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
+ }
+ if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
+ ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+ }
+ if( nPaperSizeCount == nPaperCount && pPaperSizes && pPapers )
+ {
+ for( sal_uLong i = 0; i < nPaperCount; i++ )
+ {
+ if( pPapers[ i ] == CHOOSE_DEVMODE(dmPaperSize) )
+ {
+ pSetupData->mnPaperWidth = pPaperSizes[ i ].x*10;
+ pSetupData->mnPaperHeight = pPaperSizes[ i ].y*10;
+ break;
+ }
+ }
+ }
+ if( pPapers )
+ rtl_freeMemory( pPapers );
+ if( pPaperSizes )
+ rtl_freeMemory( pPaperSizes );
+ }
+ switch( CHOOSE_DEVMODE(dmPaperSize) )
+ {
+ case( DMPAPER_LETTER ):
+ pSetupData->mePaperFormat = PAPER_LETTER;
+ break;
+ case( DMPAPER_TABLOID ):
+ pSetupData->mePaperFormat = PAPER_TABLOID;
+ break;
+ case( DMPAPER_LEDGER ):
+ pSetupData->mePaperFormat = PAPER_LEDGER;
+ break;
+ case( DMPAPER_LEGAL ):
+ pSetupData->mePaperFormat = PAPER_LEGAL;
+ break;
+ case( DMPAPER_STATEMENT ):
+ pSetupData->mePaperFormat = PAPER_STATEMENT;
+ break;
+ case( DMPAPER_EXECUTIVE ):
+ pSetupData->mePaperFormat = PAPER_EXECUTIVE;
+ break;
+ case( DMPAPER_A3 ):
+ pSetupData->mePaperFormat = PAPER_A3;
+ break;
+ case( DMPAPER_A4 ):
+ pSetupData->mePaperFormat = PAPER_A4;
+ break;
+ case( DMPAPER_A5 ):
+ pSetupData->mePaperFormat = PAPER_A5;
+ break;
+ //See http://wiki.services.openoffice.org/wiki/DefaultPaperSize
+ //i.e.
+ //http://msdn.microsoft.com/en-us/library/dd319099(VS.85).aspx
+ //DMPAPER_B4 12 B4 (JIS) 257 x 364 mm
+ //http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf
+ //also says that the MS DMPAPER_B4 is JIS, which makes most sense. And
+ //matches our Excel filter's belief about the matching XlPaperSize
+ //enumeration.
+ //
+ //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx said
+ ////"DMPAPER_B4 12 B4 (JIS) 250 x 354"
+ //which is bogus as it's either JIS 257 × 364 or ISO 250 × 353
+ //(cmc)
+ case( DMPAPER_B4 ):
+ pSetupData->mePaperFormat = PAPER_B4_JIS;
+ break;
+ case( DMPAPER_B5 ):
+ pSetupData->mePaperFormat = PAPER_B5_JIS;
+ break;
+ case( DMPAPER_QUARTO ):
+ pSetupData->mePaperFormat = PAPER_QUARTO;
+ break;
+ case( DMPAPER_10X14 ):
+ pSetupData->mePaperFormat = PAPER_10x14;
+ break;
+ case( DMPAPER_NOTE ):
+ pSetupData->mePaperFormat = PAPER_LETTER;
+ break;
+ case( DMPAPER_ENV_9 ):
+ pSetupData->mePaperFormat = PAPER_ENV_9;
+ break;
+ case( DMPAPER_ENV_10 ):
+ pSetupData->mePaperFormat = PAPER_ENV_10;
+ break;
+ case( DMPAPER_ENV_11 ):
+ pSetupData->mePaperFormat = PAPER_ENV_11;
+ break;
+ case( DMPAPER_ENV_12 ):
+ pSetupData->mePaperFormat = PAPER_ENV_12;
+ break;
+ case( DMPAPER_ENV_14 ):
+ pSetupData->mePaperFormat = PAPER_ENV_14;
+ break;
+ case( DMPAPER_CSHEET ):
+ pSetupData->mePaperFormat = PAPER_C;
+ break;
+ case( DMPAPER_DSHEET ):
+ pSetupData->mePaperFormat = PAPER_D;
+ break;
+ case( DMPAPER_ESHEET ):
+ pSetupData->mePaperFormat = PAPER_E;
+ break;
+ case( DMPAPER_ENV_DL):
+ pSetupData->mePaperFormat = PAPER_ENV_DL;
+ break;
+ case( DMPAPER_ENV_C5):
+ pSetupData->mePaperFormat = PAPER_ENV_C5;
+ break;
+ case( DMPAPER_ENV_C3):
+ pSetupData->mePaperFormat = PAPER_ENV_C3;
+ break;
+ case( DMPAPER_ENV_C4):
+ pSetupData->mePaperFormat = PAPER_ENV_C4;
+ break;
+ case( DMPAPER_ENV_C6):
+ pSetupData->mePaperFormat = PAPER_ENV_C6;
+ break;
+ case( DMPAPER_ENV_C65):
+ pSetupData->mePaperFormat = PAPER_ENV_C65;
+ break;
+ case( DMPAPER_ENV_ITALY ):
+ pSetupData->mePaperFormat = PAPER_ENV_ITALY;
+ break;
+ case( DMPAPER_ENV_MONARCH ):
+ pSetupData->mePaperFormat = PAPER_ENV_MONARCH;
+ break;
+ case( DMPAPER_ENV_PERSONAL ):
+ pSetupData->mePaperFormat = PAPER_ENV_PERSONAL;
+ break;
+ case( DMPAPER_FANFOLD_US ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_US;
+ break;
+ case( DMPAPER_FANFOLD_STD_GERMAN ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_DE;
+ break;
+ case( DMPAPER_FANFOLD_LGL_GERMAN ):
+ pSetupData->mePaperFormat = PAPER_FANFOLD_LEGAL_DE;
+ break;
+ case( DMPAPER_ISO_B4 ):
+ pSetupData->mePaperFormat = PAPER_B4_ISO;
+ break;
+ case( DMPAPER_JAPANESE_POSTCARD ):
+ pSetupData->mePaperFormat = PAPER_POSTCARD_JP;
+ break;
+ case( DMPAPER_9X11 ):
+ pSetupData->mePaperFormat = PAPER_9x11;
+ break;
+ case( DMPAPER_10X11 ):
+ pSetupData->mePaperFormat = PAPER_10x11;
+ break;
+ case( DMPAPER_15X11 ):
+ pSetupData->mePaperFormat = PAPER_15x11;
+ break;
+ case( DMPAPER_ENV_INVITE ):
+ pSetupData->mePaperFormat = PAPER_ENV_INVITE;
+ break;
+ case( DMPAPER_A_PLUS ):
+ pSetupData->mePaperFormat = PAPER_A_PLUS;
+ break;
+ case( DMPAPER_B_PLUS ):
+ pSetupData->mePaperFormat = PAPER_B_PLUS;
+ break;
+ case( DMPAPER_LETTER_PLUS ):
+ pSetupData->mePaperFormat = PAPER_LETTER_PLUS;
+ break;
+ case( DMPAPER_A4_PLUS ):
+ pSetupData->mePaperFormat = PAPER_A4_PLUS;
+ break;
+ case( DMPAPER_A2 ):
+ pSetupData->mePaperFormat = PAPER_A2;
+ break;
+ case( DMPAPER_DBL_JAPANESE_POSTCARD ):
+ pSetupData->mePaperFormat = PAPER_DOUBLEPOSTCARD_JP;
+ break;
+ case( DMPAPER_A6 ):
+ pSetupData->mePaperFormat = PAPER_A6;
+ break;
+ case( DMPAPER_B6_JIS ):
+ pSetupData->mePaperFormat = PAPER_B6_JIS;
+ break;
+ case( DMPAPER_12X11 ):
+ pSetupData->mePaperFormat = PAPER_12x11;
+ break;
+ default:
+ pSetupData->mePaperFormat = PAPER_USER;
+ break;
+ }
+ }
+
+ if( nFlags & SAL_JOBSET_DUPLEXMODE )
+ {
+ DuplexMode eDuplex = DUPLEX_UNKNOWN;
+ if( (CHOOSE_DEVMODE(dmFields) & DM_DUPLEX) )
+ {
+ if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_SIMPLEX )
+ eDuplex = DUPLEX_OFF;
+ else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_VERTICAL )
+ eDuplex = DUPLEX_LONGEDGE;
+ else if( CHOOSE_DEVMODE(dmDuplex) == DMDUP_HORIZONTAL )
+ eDuplex = DUPLEX_SHORTEDGE;
+ }
+ pSetupData->meDuplexMode = eDuplex;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, sal_uLong nFlags )
+{
+ if ( !pSetupData || !pSetupData->mpDriverData )
+ return;
+
+ DECLARE_DEVMODE( pSetupData );
+
+ // Orientation
+ if ( nFlags & SAL_JOBSET_ORIENTATION )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_ORIENTATION;
+ if ( pSetupData->meOrientation == ORIENTATION_PORTRAIT )
+ CHOOSE_DEVMODE(dmOrientation) = DMORIENT_PORTRAIT;
+ else
+ CHOOSE_DEVMODE(dmOrientation) = DMORIENT_LANDSCAPE;
+ }
+
+ // PaperBin
+ if ( nFlags & SAL_JOBSET_PAPERBIN )
+ {
+ sal_uLong nCount = ImplDeviceCaps( pPrinter, DC_BINS, NULL, pSetupData );
+
+ if ( nCount && (nCount != GDI_ERROR) )
+ {
+ WORD* pBins = (WORD*)rtl_allocateZeroMemory(nCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_BINS, (BYTE*)pBins, pSetupData );
+ CHOOSE_DEVMODE(dmFields) |= DM_DEFAULTSOURCE;
+ CHOOSE_DEVMODE(dmDefaultSource) = pBins[ pSetupData->mnPaperBin ];
+ rtl_freeMemory( pBins );
+ }
+ }
+
+ // PaperSize
+ if ( nFlags & SAL_JOBSET_PAPERSIZE )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_PAPERSIZE;
+ CHOOSE_DEVMODE(dmPaperWidth) = 0;
+ CHOOSE_DEVMODE(dmPaperLength) = 0;
+
+ switch( pSetupData->mePaperFormat )
+ {
+ case( PAPER_A2 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A2;
+ break;
+ case( PAPER_A3 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A3;
+ break;
+ case( PAPER_A4 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4;
+ break;
+ case( PAPER_A5 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A5;
+ break;
+ case( PAPER_B4_ISO):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ISO_B4;
+ break;
+ case( PAPER_LETTER ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER;
+ break;
+ case( PAPER_LEGAL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEGAL;
+ break;
+ case( PAPER_TABLOID ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_TABLOID;
+ break;
+#if 0
+ //http://msdn.microsoft.com/en-us/library/ms776398(VS.85).aspx
+ //DMPAPER_ENV_B6 is documented as:
+ //"DMPAPER_ENV_B6 35 Envelope B6 176 x 125 mm"
+ //which is the wrong way around, it is surely 125 x 176, i.e.
+ //compare DMPAPER_ENV_B4 and DMPAPER_ENV_B4 as
+ //DMPAPER_ENV_B4 33 Envelope B4 250 x 353 mm
+ //DMPAPER_ENV_B5 34 Envelope B5 176 x 250 mm
+ case( PAPER_B6_ISO ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_B6;
+ break;
+#endif
+ case( PAPER_ENV_C4 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C4;
+ break;
+ case( PAPER_ENV_C5 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C5;
+ break;
+ case( PAPER_ENV_C6 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C6;
+ break;
+ case( PAPER_ENV_C65 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C65;
+ break;
+ case( PAPER_ENV_DL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_DL;
+ break;
+ case( PAPER_C ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_CSHEET;
+ break;
+ case( PAPER_D ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DSHEET;
+ break;
+ case( PAPER_E ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ESHEET;
+ break;
+ case( PAPER_EXECUTIVE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_EXECUTIVE;
+ break;
+ case( PAPER_FANFOLD_LEGAL_DE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_LGL_GERMAN;
+ break;
+ case( PAPER_ENV_MONARCH ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_MONARCH;
+ break;
+ case( PAPER_ENV_PERSONAL ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_PERSONAL;
+ break;
+ case( PAPER_ENV_9 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_9;
+ break;
+ case( PAPER_ENV_10 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_10;
+ break;
+ case( PAPER_ENV_11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_11;
+ break;
+ case( PAPER_ENV_12 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_12;
+ break;
+ //See the comments on DMPAPER_B4 above
+ case( PAPER_B4_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B4;
+ break;
+ case( PAPER_B5_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B5;
+ break;
+ case( PAPER_B6_JIS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B6_JIS;
+ break;
+ case( PAPER_LEDGER ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LEDGER;
+ break;
+ case( PAPER_STATEMENT ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_STATEMENT;
+ break;
+ case( PAPER_10x14 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X14;
+ break;
+ case( PAPER_ENV_14 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_14;
+ break;
+ case( PAPER_ENV_C3 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_C3;
+ break;
+ case( PAPER_ENV_ITALY ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_ITALY;
+ break;
+ case( PAPER_FANFOLD_US ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_US;
+ break;
+ case( PAPER_FANFOLD_DE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_FANFOLD_STD_GERMAN;
+ break;
+ case( PAPER_POSTCARD_JP ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_JAPANESE_POSTCARD;
+ break;
+ case( PAPER_9x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_9X11;
+ break;
+ case( PAPER_10x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_10X11;
+ break;
+ case( PAPER_15x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_15X11;
+ break;
+ case( PAPER_ENV_INVITE ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_ENV_INVITE;
+ break;
+ case( PAPER_A_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A_PLUS;
+ break;
+ case( PAPER_B_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_B_PLUS;
+ break;
+ case( PAPER_LETTER_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_LETTER_PLUS;
+ break;
+ case( PAPER_A4_PLUS ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A4_PLUS;
+ break;
+ case( PAPER_DOUBLEPOSTCARD_JP ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_DBL_JAPANESE_POSTCARD;
+ break;
+ case( PAPER_A6 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_A6;
+ break;
+ case( PAPER_12x11 ):
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_12X11;
+ break;
+ default:
+ {
+ short nPaper = 0;
+ sal_uLong nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData );
+ WORD* pPapers = NULL;
+ sal_uLong nPaperSizeCount = ImplDeviceCaps( pPrinter, DC_PAPERSIZE, NULL, pSetupData );
+ POINT* pPaperSizes = NULL;
+ DWORD nLandscapeAngle = ImplDeviceCaps( pPrinter, DC_ORIENTATION, NULL, pSetupData );
+ if ( nPaperCount && (nPaperCount != GDI_ERROR) )
+ {
+ pPapers = (WORD*)rtl_allocateZeroMemory(nPaperCount*sizeof(WORD));
+ ImplDeviceCaps( pPrinter, DC_PAPERS, (BYTE*)pPapers, pSetupData );
+ }
+ if ( nPaperSizeCount && (nPaperSizeCount != GDI_ERROR) )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nPaperSizeCount*sizeof(POINT));
+ ImplDeviceCaps( pPrinter, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+ }
+ if ( (nPaperSizeCount == nPaperCount) && pPapers && pPaperSizes )
+ {
+ PaperInfo aInfo(pSetupData->mnPaperWidth, pSetupData->mnPaperHeight);
+ // compare paper formats and select a good match
+ for ( sal_uLong i = 0; i < nPaperCount; i++ )
+ {
+ if ( aInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)))
+ {
+ nPaper = pPapers[i];
+ break;
+ }
+ }
+
+ // If the printer supports landscape orientation, check paper sizes again
+ // with landscape orientation. This is necessary as a printer driver provides
+ // all paper sizes with portrait orientation only!!
+ if ( !nPaper && nLandscapeAngle != 0 )
+ {
+ PaperInfo aRotatedInfo(pSetupData->mnPaperHeight, pSetupData->mnPaperWidth);
+ for ( sal_uLong i = 0; i < nPaperCount; i++ )
+ {
+ if ( aRotatedInfo.sloppyEqual(PaperInfo(pPaperSizes[i].x*10, pPaperSizes[i].y*10)) )
+ {
+ nPaper = pPapers[i];
+ break;
+ }
+ }
+ }
+
+ if ( nPaper )
+ CHOOSE_DEVMODE(dmPaperSize) = nPaper;
+ }
+
+ if ( !nPaper )
+ {
+ CHOOSE_DEVMODE(dmFields) |= DM_PAPERLENGTH | DM_PAPERWIDTH;
+ CHOOSE_DEVMODE(dmPaperSize) = DMPAPER_USER;
+ CHOOSE_DEVMODE(dmPaperWidth) = (short)(pSetupData->mnPaperWidth/10);
+ CHOOSE_DEVMODE(dmPaperLength) = (short)(pSetupData->mnPaperHeight/10);
+ }
+
+ if ( pPapers )
+ rtl_freeMemory(pPapers);
+ if ( pPaperSizes )
+ rtl_freeMemory(pPaperSizes);
+
+ break;
+ }
+ }
+ }
+ if( (nFlags & SAL_JOBSET_DUPLEXMODE) )
+ {
+ switch( pSetupData->meDuplexMode )
+ {
+ case DUPLEX_OFF:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_SIMPLEX;
+ break;
+ case DUPLEX_SHORTEDGE:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_HORIZONTAL;
+ break;
+ case DUPLEX_LONGEDGE:
+ CHOOSE_DEVMODE(dmFields) |= DM_DUPLEX;
+ CHOOSE_DEVMODE(dmDuplex) = DMDUP_VERTICAL;
+ break;
+ case DUPLEX_UNKNOWN:
+ break;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static HDC ImplCreateICW_WithCatch( LPWSTR pDriver,
+ LPCWSTR pDevice,
+ LPDEVMODEW pDevMode )
+{
+ HDC hDC = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ hDC = CreateICW( pDriver, pDevice, 0, pDevMode );
+ CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
+ return hDC;
+}
+
+static HDC ImplCreateICA_WithCatch( char* pDriver,
+ char* pDevice,
+ LPDEVMODEA pDevMode )
+{
+ HDC hDC = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ hDC = CreateICA( pDriver, pDevice, 0, pDevMode );
+ CATCH_DRIVER_EX_END_2( "exception in CreateICW" );
+ return hDC;
+}
+
+
+static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
+{
+ HDC hDC = 0;
+ if( aSalShlData.mbWPrinter )
+ {
+ LPDEVMODEW pDevMode;
+ if ( pSetupData && pSetupData->mpDriverData )
+ pDevMode = SAL_DEVMODE_W( pSetupData );
+ else
+ pDevMode = NULL;
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
+ // pl: does this hold true for Unicode functions ?
+ if( pPrinter->maDriverName.Len() > 2048 || pPrinter->maDeviceName.Len() > 2048 )
+ return 0;
+ sal_Unicode pDriverName[ 4096 ];
+ sal_Unicode pDeviceName[ 4096 ];
+ rtl_copyMemory( pDriverName, pPrinter->maDriverName.GetBuffer(), pPrinter->maDriverName.Len()*sizeof(sal_Unicode));
+ memset( pDriverName+pPrinter->maDriverName.Len(), 0, 32 );
+ rtl_copyMemory( pDeviceName, pPrinter->maDeviceName.GetBuffer(), pPrinter->maDeviceName.Len()*sizeof(sal_Unicode));
+ memset( pDeviceName+pPrinter->maDeviceName.Len(), 0, 32 );
+ hDC = ImplCreateICW_WithCatch( reinterpret_cast< LPWSTR >(pDriverName),
+ reinterpret_cast< LPCWSTR >(pDeviceName),
+ pDevMode );
+ }
+ else
+ {
+ LPDEVMODEA pDevMode;
+ if ( pSetupData && pSetupData->mpDriverData )
+ pDevMode = SAL_DEVMODE_A( pSetupData );
+ else
+ pDevMode = NULL;
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateIC, although declared const - so provide some space
+ ByteString aDriver ( ImplSalGetWinAnsiString( pPrinter->maDriverName, TRUE ) );
+ ByteString aDevice ( ImplSalGetWinAnsiString( pPrinter->maDeviceName, TRUE ) );
+ int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
+ // #125813# under some circumstances many printer drivers really
+ // seem to have a problem with the names and their conversions.
+ // We need to get on to of this, but haven't been able to reproduce
+ // the problem yet. Put the names on the stack so we get them
+ // with an eventual crash report.
+ if( n >= 2048 )
+ return 0;
+ n += 2048;
+ char lpszDriverName[ 4096 ];
+ char lpszDeviceName[ 4096 ];
+ strncpy( lpszDriverName, aDriver.GetBuffer(), n );
+ strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
+ // HDU: the crashes usually happen in a MBCS to unicode conversion,
+ // so I suspect the MBCS string's end is not properly recognized.
+ // The longest MBCS encoding I'm aware of has six bytes per code
+ // => add a couple of zeroes...
+ memset( lpszDriverName+aDriver.Len(), 0, 16 );
+ memset( lpszDeviceName+aDevice.Len(), 0, 16 );
+ hDC = ImplCreateICA_WithCatch( lpszDriverName,
+ lpszDeviceName,
+ pDevMode );
+ }
+ return hDC;
+}
+
+// -----------------------------------------------------------------------
+
+static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC )
+{
+ WinSalGraphics* pGraphics = new WinSalGraphics;
+ pGraphics->SetLayout( 0 );
+ pGraphics->mhDC = hDC;
+ pGraphics->mhWnd = 0;
+ pGraphics->mbPrinter = TRUE;
+ pGraphics->mbVirDev = FALSE;
+ pGraphics->mbWindow = FALSE;
+ pGraphics->mbScreen = FALSE;
+ ImplSalInitGraphics( pGraphics );
+ return pGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData )
+{
+ HDC hNewDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
+ if ( !hNewDC )
+ return FALSE;
+
+ if ( pPrinter->mpGraphics )
+ {
+ ImplSalDeInitGraphics( pPrinter->mpGraphics );
+ DeleteDC( pPrinter->mpGraphics->mhDC );
+ delete pPrinter->mpGraphics;
+ }
+
+ pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hNewDC );
+ pPrinter->mhDC = hNewDC;
+
+ return TRUE;
+}
+
+// =======================================================================
+
+SalInfoPrinter* WinSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
+ ImplJobSetup* pSetupData )
+{
+ WinSalInfoPrinter* pPrinter = new WinSalInfoPrinter;
+ if( ! pQueueInfo->mpSysData )
+ GetPrinterQueueState( pQueueInfo );
+ pPrinter->maDriverName = pQueueInfo->maDriver;
+ pPrinter->maDeviceName = pQueueInfo->maPrinterName;
+ pPrinter->maPortName = pQueueInfo->mpSysData ?
+ *(String*)(pQueueInfo->mpSysData)
+ : String();
+
+ // check if the provided setup data match the actual printer
+ ImplTestSalJobSetup( pPrinter, pSetupData, TRUE );
+
+ HDC hDC = ImplCreateSalPrnIC( pPrinter, pSetupData );
+ if ( !hDC )
+ {
+ delete pPrinter;
+ return NULL;
+ }
+
+ pPrinter->mpGraphics = ImplCreateSalPrnGraphics( hDC );
+ pPrinter->mhDC = hDC;
+ if ( !pSetupData->mpDriverData )
+ ImplUpdateSalJobSetup( pPrinter, pSetupData, FALSE, NULL );
+ ImplDevModeToJobSetup( pPrinter, pSetupData, SAL_JOBSET_ALL );
+ pSetupData->mnSystem = JOBSETUP_SYSTEM_WINDOWS;
+
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+WinSalInfoPrinter::WinSalInfoPrinter() :
+ mpGraphics( NULL ),
+ mhDC( 0 ),
+ mbGraphics( FALSE )
+{
+ m_bPapersInit = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalInfoPrinter::~WinSalInfoPrinter()
+{
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ DeleteDC( mpGraphics->mhDC );
+ delete mpGraphics;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData )
+{
+ m_aPaperFormats.clear();
+
+ DWORD nCount = ImplDeviceCaps( this, DC_PAPERSIZE, NULL, pSetupData );
+ if( nCount == GDI_ERROR )
+ nCount = 0;
+
+ POINT* pPaperSizes = NULL;
+ if( nCount )
+ {
+ pPaperSizes = (POINT*)rtl_allocateZeroMemory(nCount*sizeof(POINT));
+ ImplDeviceCaps( this, DC_PAPERSIZE, (BYTE*)pPaperSizes, pSetupData );
+
+ if( aSalShlData.mbWPrinter )
+ {
+ sal_Unicode* pNamesBuffer = (sal_Unicode*)rtl_allocateMemory(nCount*64*sizeof(sal_Unicode));
+ ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
+ for( DWORD i = 0; i < nCount; ++i )
+ {
+ PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
+ m_aPaperFormats.push_back( aInfo );
+ }
+ rtl_freeMemory( pNamesBuffer );
+ }
+ else
+ {
+ char* pNamesBuffer = (char*)rtl_allocateMemory(nCount*64);
+ ImplDeviceCaps( this, DC_PAPERNAMES, (BYTE*)pNamesBuffer, pSetupData );
+ for( DWORD i = 0; i < nCount; ++i )
+ {
+ PaperInfo aInfo(pPaperSizes[i].x * 10, pPaperSizes[i].y * 10);
+ m_aPaperFormats.push_back( aInfo );
+ }
+ rtl_freeMemory( pNamesBuffer );
+ }
+ rtl_freeMemory( pPaperSizes );
+ }
+
+ m_bPapersInit = true;
+}
+
+// -----------------------------------------------------------------------
+
+int WinSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData )
+{
+ int nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
+
+ if( nRet != GDI_ERROR )
+ return nRet * 10;
+ else
+ return 900; // guess
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalInfoPrinter::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pSetupData )
+{
+ if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, static_cast<WinSalFrame*>(pFrame) ) )
+ {
+ ImplDevModeToJobSetup( this, pSetupData, SAL_JOBSET_ALL );
+ return ImplUpdateSalPrnIC( this, pSetupData );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData )
+{
+ if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) )
+ return FALSE;
+ return ImplUpdateSalPrnIC( this, pSetupData );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalInfoPrinter::SetData( sal_uLong nFlags, ImplJobSetup* pSetupData )
+{
+ ImplJobSetupToDevMode( this, pSetupData, nFlags );
+ if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) )
+ {
+ ImplDevModeToJobSetup( this, pSetupData, nFlags );
+ return ImplUpdateSalPrnIC( this, pSetupData );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong WinSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pSetupData )
+{
+ DWORD nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ else
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pSetupData, sal_uLong nPaperBin )
+{
+ XubString aPaperBinName;
+
+ DWORD nBins = ImplDeviceCaps( this, DC_BINNAMES, NULL, pSetupData );
+ if ( (nPaperBin < nBins) && (nBins != GDI_ERROR) )
+ {
+ if( aSalShlData.mbWPrinter )
+ {
+ sal_Unicode* pBuffer = new sal_Unicode[nBins*24];
+ DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ aPaperBinName = pBuffer + (nPaperBin*24);
+ delete [] pBuffer;
+ }
+ else
+ {
+ char* pBuffer = new char[nBins*24];
+ DWORD nRet = ImplDeviceCaps( this, DC_BINNAMES, (BYTE*)pBuffer, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ aPaperBinName = ImplSalGetUniString( (const char*)(pBuffer + (nPaperBin*24)) );
+ delete [] pBuffer;
+ }
+ }
+
+ return aPaperBinName;
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, sal_uInt16 nType )
+{
+ DWORD nRet;
+
+ switch ( nType )
+ {
+ case PRINTER_CAPABILITIES_SUPPORTDIALOG:
+ return TRUE;
+ case PRINTER_CAPABILITIES_COPIES:
+ nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ return 0;
+ case PRINTER_CAPABILITIES_COLLATECOPIES:
+ if ( aSalShlData.mbW40 )
+ {
+ nRet = ImplDeviceCaps( this, DC_COLLATE, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ {
+ nRet = ImplDeviceCaps( this, DC_COPIES, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return nRet;
+ }
+ }
+ return 0;
+
+ case PRINTER_CAPABILITIES_SETORIENTATION:
+ nRet = ImplDeviceCaps( this, DC_ORIENTATION, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+
+ case PRINTER_CAPABILITIES_SETPAPERBIN:
+ nRet = ImplDeviceCaps( this, DC_BINS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+
+ case PRINTER_CAPABILITIES_SETPAPERSIZE:
+ case PRINTER_CAPABILITIES_SETPAPER:
+ nRet = ImplDeviceCaps( this, DC_PAPERS, NULL, pSetupData );
+ if ( nRet && (nRet != GDI_ERROR) )
+ return TRUE;
+ return FALSE;
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
+ long& rOutWidth, long& rOutHeight,
+ long& rPageOffX, long& rPageOffY,
+ long& rPageWidth, long& rPageHeight )
+{
+ HDC hDC = mhDC;
+
+ rOutWidth = GetDeviceCaps( hDC, HORZRES );
+ rOutHeight = GetDeviceCaps( hDC, VERTRES );
+
+ rPageOffX = GetDeviceCaps( hDC, PHYSICALOFFSETX );
+ rPageOffY = GetDeviceCaps( hDC, PHYSICALOFFSETY );
+ rPageWidth = GetDeviceCaps( hDC, PHYSICALWIDTH );
+ rPageHeight = GetDeviceCaps( hDC, PHYSICALHEIGHT );
+}
+
+// =======================================================================
+
+SalPrinter* WinSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
+{
+ WinSalPrinter* pPrinter = new WinSalPrinter;
+ pPrinter->mpInfoPrinter = static_cast<WinSalInfoPrinter*>(pInfoPrinter);
+ return pPrinter;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyPrinter( SalPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+// =======================================================================
+
+BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ )
+{
+ SalData* pSalData = GetSalData();
+ WinSalPrinter* pPrinter;
+ sal_Bool bWhile = TRUE;
+ int i = 0;
+
+ do
+ {
+ // Messages verarbeiten
+ MSG aMsg;
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplDispatchMessage( &aMsg );
+ }
+ i++;
+ if ( i > 15 )
+ bWhile = FALSE;
+ }
+ else
+ bWhile = FALSE;
+
+ pPrinter = pSalData->mpFirstPrinter;
+ while ( pPrinter )
+ {
+ if( pPrinter->mhDC == hPrnDC )
+ break;
+
+ pPrinter = pPrinter->mpNextPrinter;
+ }
+
+ if ( !pPrinter || pPrinter->mbAbort )
+ return FALSE;
+ }
+ while ( bWhile );
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+static LPDEVMODEA ImplSalSetCopies( LPDEVMODEA pDevMode, sal_uLong nCopies, sal_Bool bCollate )
+{
+ LPDEVMODEA pNewDevMode = pDevMode;
+ if ( pDevMode && (nCopies > 1) )
+ {
+ if ( nCopies > 32765 )
+ nCopies = 32765;
+ sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
+ pNewDevMode = (LPDEVMODEA)rtl_allocateMemory( nDevSize );
+ memcpy( pNewDevMode, pDevMode, nDevSize );
+ pDevMode = pNewDevMode;
+ pDevMode->dmFields |= DM_COPIES;
+ pDevMode->dmCopies = (short)(sal_uInt16)nCopies;
+ if ( aSalShlData.mbW40 )
+ {
+ pDevMode->dmFields |= DM_COLLATE;
+ if ( bCollate )
+ pDevMode->dmCollate = DMCOLLATE_TRUE;
+ else
+ pDevMode->dmCollate = DMCOLLATE_FALSE;
+ }
+ }
+
+ return pNewDevMode;
+}
+
+static LPDEVMODEW ImplSalSetCopies( LPDEVMODEW pDevMode, sal_uLong nCopies, sal_Bool bCollate )
+{
+ LPDEVMODEW pNewDevMode = pDevMode;
+ if ( pDevMode && (nCopies > 1) )
+ {
+ if ( nCopies > 32765 )
+ nCopies = 32765;
+ sal_uLong nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra;
+ pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize );
+ memcpy( pNewDevMode, pDevMode, nDevSize );
+ pDevMode = pNewDevMode;
+ pDevMode->dmFields |= DM_COPIES;
+ pDevMode->dmCopies = (short)(sal_uInt16)nCopies;
+ if ( aSalShlData.mbW40 )
+ {
+ pDevMode->dmFields |= DM_COLLATE;
+ if ( bCollate )
+ pDevMode->dmCollate = DMCOLLATE_TRUE;
+ else
+ pDevMode->dmCollate = DMCOLLATE_FALSE;
+ }
+ }
+
+ return pNewDevMode;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalPrinter::WinSalPrinter() :
+ mpGraphics( NULL ),
+ mpInfoPrinter( NULL ),
+ mpNextPrinter( NULL ),
+ mhDC( 0 ),
+ mnError( 0 ),
+ mnCopies( 0 ),
+ mbCollate( FALSE ),
+ mbAbort( FALSE ),
+ mbValid( true )
+{
+ SalData* pSalData = GetSalData();
+ // insert printer in printerlist
+ mpNextPrinter = pSalData->mpFirstPrinter;
+ pSalData->mpFirstPrinter = this;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalPrinter::~WinSalPrinter()
+{
+ SalData* pSalData = GetSalData();
+
+ // release DC if there is one still around because of AbortJob
+ HDC hDC = mhDC;
+ if ( hDC )
+ {
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ }
+
+ DeleteDC( hDC );
+ }
+
+ // remove printer from printerlist
+ if ( this == pSalData->mpFirstPrinter )
+ pSalData->mpFirstPrinter = mpNextPrinter;
+ else
+ {
+ WinSalPrinter* pTempPrinter = pSalData->mpFirstPrinter;
+
+ while( pTempPrinter->mpNextPrinter != this )
+ pTempPrinter = pTempPrinter->mpNextPrinter;
+
+ pTempPrinter->mpNextPrinter = mpNextPrinter;
+ }
+ mbValid = false;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalPrinter::markInvalid()
+{
+ mbValid = false;
+}
+
+// -----------------------------------------------------------------------
+
+// need wrappers for StarTocW/A to use structured exception handling
+// since SEH does not mix with standard exception handling's cleanup
+static int lcl_StartDocW( HDC hDC, DOCINFOW* pInfo, WinSalPrinter* pPrt )
+{
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartDocW( hDC, pInfo );
+ CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
+ return nRet;
+}
+
+static int lcl_StartDocA( HDC hDC, DOCINFOA* pInfo, WinSalPrinter* pPrt )
+{
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartDocA( hDC, pInfo );
+ CATCH_DRIVER_EX_END( "exception in StartDocW", pPrt );
+ return nRet;
+}
+
+sal_Bool WinSalPrinter::StartJob( const XubString* pFileName,
+ const XubString& rJobName,
+ const XubString&,
+ sal_uLong nCopies,
+ bool bCollate,
+ bool /*bDirect*/,
+ ImplJobSetup* pSetupData )
+{
+ mnError = 0;
+ mbAbort = FALSE;
+ mnCopies = nCopies;
+ mbCollate = bCollate;
+
+ LPDEVMODEA pOrgDevModeA = NULL;
+ LPDEVMODEA pDevModeA = NULL;
+ LPDEVMODEW pOrgDevModeW = NULL;
+ LPDEVMODEW pDevModeW = NULL;
+ HDC hDC = 0;
+ if( aSalShlData.mbWPrinter )
+ {
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
+ pDevModeW = ImplSalSetCopies( pOrgDevModeW, nCopies, bCollate );
+ }
+ else
+ pDevModeW = NULL;
+
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
+ sal_Unicode aDrvBuf[4096];
+ sal_Unicode aDevBuf[4096];
+ rtl_copyMemory( aDrvBuf, mpInfoPrinter->maDriverName.GetBuffer(), (mpInfoPrinter->maDriverName.Len()+1)*sizeof(sal_Unicode));
+ rtl_copyMemory( aDevBuf, mpInfoPrinter->maDeviceName.GetBuffer(), (mpInfoPrinter->maDeviceName.Len()+1)*sizeof(sal_Unicode));
+ hDC = CreateDCW( reinterpret_cast<LPCWSTR>(aDrvBuf),
+ reinterpret_cast<LPCWSTR>(aDevBuf),
+ NULL,
+ pDevModeW );
+
+ if ( pDevModeW != pOrgDevModeW )
+ rtl_freeMemory( pDevModeW );
+ }
+ else
+ {
+ if ( pSetupData && pSetupData->mpDriverData )
+ {
+ pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
+ pDevModeA = ImplSalSetCopies( pOrgDevModeA, nCopies, bCollate );
+ }
+ else
+ pDevModeA = NULL;
+
+ // #95347 some buggy drivers (eg, OKI) write to those buffers in CreateDC, although declared const - so provide some space
+ ByteString aDriver ( ImplSalGetWinAnsiString( mpInfoPrinter->maDriverName, TRUE ) );
+ ByteString aDevice ( ImplSalGetWinAnsiString( mpInfoPrinter->maDeviceName, TRUE ) );
+ int n = aDriver.Len() > aDevice.Len() ? aDriver.Len() : aDevice.Len();
+ n += 2048;
+ char *lpszDriverName = new char[n];
+ char *lpszDeviceName = new char[n];
+ strncpy( lpszDriverName, aDriver.GetBuffer(), n );
+ strncpy( lpszDeviceName, aDevice.GetBuffer(), n );
+ hDC = CreateDCA( lpszDriverName,
+ lpszDeviceName,
+ NULL,
+ pDevModeA );
+
+ delete [] lpszDriverName;
+ delete [] lpszDeviceName;
+
+ if ( pDevModeA != pOrgDevModeA )
+ rtl_freeMemory( pDevModeA );
+ }
+
+ if ( !hDC )
+ {
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+
+ // make sure mhDC is set before the printer driver may call our abortproc
+ mhDC = hDC;
+ if ( SetAbortProc( hDC, SalPrintAbortProc ) <= 0 )
+ {
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+
+ mnError = 0;
+ mbAbort = FALSE;
+
+ // Wegen Telocom Balloon Fax-Treiber, der uns unsere Messages
+ // ansonsten oefters schickt, versuchen wir vorher alle
+ // zu verarbeiten und dann eine Dummy-Message reinstellen
+ sal_Bool bWhile = TRUE;
+ int i = 0;
+ do
+ {
+ // Messages verarbeiten
+ MSG aMsg;
+ if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
+ {
+ if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
+ {
+ TranslateMessage( &aMsg );
+ ImplDispatchMessage( &aMsg );
+ }
+
+ i++;
+ if ( i > 15 )
+ bWhile = FALSE;
+ }
+ else
+ bWhile = FALSE;
+ }
+ while ( bWhile );
+ ImplPostMessage( GetSalData()->mpFirstInstance->mhComWnd, SAL_MSG_DUMMY, 0, 0 );
+
+ // bring up a file choser if printing to file port but no file name given
+ OUString aOutFileName;
+ if( mpInfoPrinter->maPortName.EqualsIgnoreCaseAscii( "FILE:" ) && !(pFileName && pFileName->Len()) )
+ {
+
+ uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
+ if( xFactory.is() )
+ {
+ uno::Reference< XFilePicker > xFilePicker( xFactory->createInstance(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.dialogs.FilePicker" ) ) ),
+ UNO_QUERY );
+ DBG_ASSERT( xFilePicker.is(), "could not get FilePicker service" );
+
+ uno::Reference< XInitialization > xInit( xFilePicker, UNO_QUERY );
+ uno::Reference< XFilterManager > xFilterMgr( xFilePicker, UNO_QUERY );
+ if( xInit.is() && xFilePicker.is() && xFilterMgr.is() )
+ {
+ Sequence< Any > aServiceType( 1 );
+ aServiceType[0] <<= TemplateDescription::FILESAVE_SIMPLE;
+ xInit->initialize( aServiceType );
+ if( xFilePicker->execute() == ExecutableDialogResults::OK )
+ {
+ Sequence< OUString > aPathSeq( xFilePicker->getFiles() );
+ INetURLObject aObj( aPathSeq[0] );
+ // we're using ansi calls (StartDocA) so convert the string
+ aOutFileName = aObj.PathToFileName();
+ }
+ else
+ {
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if( aSalShlData.mbWPrinter )
+ {
+ DOCINFOW aInfo;
+ memset( &aInfo, 0, sizeof( DOCINFOW ) );
+ aInfo.cbSize = sizeof( aInfo );
+ aInfo.lpszDocName = (LPWSTR)rJobName.GetBuffer();
+ if ( pFileName || aOutFileName.getLength() )
+ {
+ if ( (pFileName && pFileName->Len()) || aOutFileName.getLength() )
+ {
+ aInfo.lpszOutput = (LPWSTR)( (pFileName && pFileName->Len()) ? pFileName->GetBuffer() : aOutFileName.getStr());
+ }
+ else
+ aInfo.lpszOutput = L"FILE:";
+ }
+ else
+ aInfo.lpszOutput = NULL;
+
+ // start Job
+ int nRet = lcl_StartDocW( hDC, &aInfo, this );
+
+ if ( nRet <= 0 )
+ {
+ long nError = GetLastError();
+ if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+ }
+ else
+ {
+ // Both strings must exist, if StartJob() is called
+ ByteString aJobName( ImplSalGetWinAnsiString( rJobName, TRUE ) );
+ ByteString aFileName;
+
+ DOCINFOA aInfo;
+ memset( &aInfo, 0, sizeof( DOCINFOA ) );
+ aInfo.cbSize = sizeof( aInfo );
+ aInfo.lpszDocName = (LPCSTR)aJobName.GetBuffer();
+ if ( pFileName || aOutFileName.getLength() )
+ {
+ if ( pFileName->Len() || aOutFileName.getLength() )
+ {
+ aFileName = ImplSalGetWinAnsiString( pFileName ? *pFileName : static_cast<const XubString>(aOutFileName), TRUE );
+ aInfo.lpszOutput = (LPCSTR)aFileName.GetBuffer();
+ }
+ else
+ aInfo.lpszOutput = "FILE:";
+ }
+ else
+ aInfo.lpszOutput = NULL;
+
+ // start Job
+ int nRet = lcl_StartDocA( hDC, &aInfo, this );
+ if ( nRet <= 0 )
+ {
+ long nError = GetLastError();
+ if ( (nRet == SP_USERABORT) || (nRet == SP_APPABORT) || (nError == ERROR_PRINT_CANCELLED) || (nError == ERROR_CANCELLED) )
+ mnError = SAL_PRINTER_ERROR_ABORT;
+ else
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalPrinter::EndJob()
+{
+ DWORD err = 0;
+ HDC hDC = mhDC;
+ if ( isValid() && hDC )
+ {
+ if ( mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ // #i54419# Windows fax printer brings up a dialog in EndDoc
+ // which text previously copied in soffice process can be
+ // pasted to -> deadlock due to mutex not released.
+ // it should be safe to release the yield mutex over the EndDoc
+ // call, however the real solution is supposed to be the threading
+ // framework yet to come.
+ SalData* pSalData = GetSalData();
+ sal_uLong nAcquire = pSalData->mpFirstInstance->ReleaseYieldMutex();
+ CATCH_DRIVER_EX_BEGIN;
+ if( ::EndDoc( hDC ) <= 0 )
+ err = GetLastError();
+ CATCH_DRIVER_EX_END( "exception in EndDoc", this );
+
+ pSalData->mpFirstInstance->AcquireYieldMutex( nAcquire );
+ DeleteDC( hDC );
+ mhDC = 0;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalPrinter::AbortJob()
+{
+ mbAbort = TRUE;
+
+ // Abort asyncron ausloesen
+ HDC hDC = mhDC;
+ if ( hDC )
+ {
+ SalData* pSalData = GetSalData();
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_PRINTABORTJOB, (WPARAM)hDC, 0 );
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalPrinterAbortJobAsync( HDC hPrnDC )
+{
+ SalData* pSalData = GetSalData();
+ WinSalPrinter* pPrinter = pSalData->mpFirstPrinter;
+
+ // Feststellen, ob Printer noch existiert
+ while ( pPrinter )
+ {
+ if ( pPrinter->mhDC == hPrnDC )
+ break;
+
+ pPrinter = pPrinter->mpNextPrinter;
+ }
+
+ // Wenn Printer noch existiert, dann den Job abbrechen
+ if ( pPrinter )
+ {
+ HDC hDC = pPrinter->mhDC;
+ if ( hDC )
+ {
+ if ( pPrinter->mpGraphics )
+ {
+ ImplSalDeInitGraphics( pPrinter->mpGraphics );
+ delete pPrinter->mpGraphics;
+ pPrinter->mpGraphics = NULL;
+ }
+
+ CATCH_DRIVER_EX_BEGIN;
+ ::AbortDoc( hDC );
+ CATCH_DRIVER_EX_END( "exception in AbortDoc", pPrinter );
+
+ DeleteDC( hDC );
+ pPrinter->mhDC = 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalPrinter::StartPage( ImplJobSetup* pSetupData, sal_Bool bNewJobData )
+{
+ if( ! isValid() || mhDC == 0 )
+ return NULL;
+
+ HDC hDC = mhDC;
+ if ( pSetupData && pSetupData->mpDriverData && bNewJobData )
+ {
+ if( aSalShlData.mbWPrinter )
+ {
+ LPDEVMODEW pOrgDevModeW;
+ LPDEVMODEW pDevModeW;
+ pOrgDevModeW = SAL_DEVMODE_W( pSetupData );
+ pDevModeW = ImplSalSetCopies( pOrgDevModeW, mnCopies, mbCollate );
+ ResetDCW( hDC, pDevModeW );
+ if ( pDevModeW != pOrgDevModeW )
+ rtl_freeMemory( pDevModeW );
+ }
+ else
+ {
+ LPDEVMODEA pOrgDevModeA;
+ LPDEVMODEA pDevModeA;
+ pOrgDevModeA = SAL_DEVMODE_A( pSetupData );
+ pDevModeA = ImplSalSetCopies( pOrgDevModeA, mnCopies, mbCollate );
+ ResetDCA( hDC, pDevModeA );
+ if ( pDevModeA != pOrgDevModeA )
+ rtl_freeMemory( pDevModeA );
+ }
+ }
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::StartPage( hDC );
+ CATCH_DRIVER_EX_END( "exception in StartPage", this );
+
+ if ( nRet <= 0 )
+ {
+ GetLastError();
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return NULL;
+ }
+
+ // Hack to work around old PostScript printer drivers optimizing away empty pages
+ // TODO: move into ImplCreateSalPrnGraphics()?
+ HPEN hTempPen = SelectPen( hDC, GetStockPen( NULL_PEN ) );
+ HBRUSH hTempBrush = SelectBrush( hDC, GetStockBrush( NULL_BRUSH ) );
+ WIN_Rectangle( hDC, -8000, -8000, -7999, -7999 );
+ SelectPen( hDC, hTempPen );
+ SelectBrush( hDC, hTempBrush );
+
+ mpGraphics = ImplCreateSalPrnGraphics( hDC );
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalPrinter::EndPage()
+{
+ HDC hDC = mhDC;
+ if ( hDC && mpGraphics )
+ {
+ ImplSalDeInitGraphics( mpGraphics );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ if( ! isValid() )
+ return FALSE;
+
+ int nRet = 0;
+ CATCH_DRIVER_EX_BEGIN;
+ nRet = ::EndPage( hDC );
+ CATCH_DRIVER_EX_END( "exception in EndPage", this );
+
+ if ( nRet > 0 )
+ return TRUE;
+ else
+ {
+ GetLastError();
+ mnError = SAL_PRINTER_ERROR_GENERALERROR;
+ return FALSE;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong WinSalPrinter::GetErrorCode()
+{
+ return mnError;
+}
diff --git a/vcl/win/source/gdi/salvd.cxx b/vcl/win/source/gdi/salvd.cxx
new file mode 100755
index 000000000000..94f08a33179c
--- /dev/null
+++ b/vcl/win/source/gdi/salvd.cxx
@@ -0,0 +1,259 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/svwin.h>
+
+#include <vcl/sysdata.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salgdi.h>
+#include <win/salvd.h>
+
+// =======================================================================
+
+static HBITMAP ImplCreateVirDevBitmap( HDC hDC, long nDX, long nDY,
+ sal_uInt16 nBitCount )
+{
+ HBITMAP hBitmap;
+
+ if ( nBitCount == 1 )
+ {
+ hBitmap = CreateBitmap( (int)nDX, (int)nDY, 1, 1, NULL );
+ }
+ else
+ {
+ // #146839# Don't use CreateCompatibleBitmap() - there seem to
+ // be build-in limits for those HBITMAPs, at least this fails
+ // rather often on large displays/multi-monitor setups.
+ BITMAPINFO aBitmapInfo;
+ aBitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
+ aBitmapInfo.bmiHeader.biWidth = nDX;
+ aBitmapInfo.bmiHeader.biHeight = nDY;
+ aBitmapInfo.bmiHeader.biPlanes = 1;
+ aBitmapInfo.bmiHeader.biBitCount = (WORD)GetDeviceCaps( hDC,
+ BITSPIXEL );
+ aBitmapInfo.bmiHeader.biCompression = BI_RGB;
+ aBitmapInfo.bmiHeader.biSizeImage = 0;
+ aBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ aBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ aBitmapInfo.bmiHeader.biClrUsed = 0;
+ aBitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pDummy;
+ hBitmap = CreateDIBSection( hDC, &aBitmapInfo,
+ DIB_RGB_COLORS, &pDummy, NULL,
+ 0 );
+ }
+
+ return hBitmap;
+}
+
+// =======================================================================
+
+SalVirtualDevice* WinSalInstance::CreateVirtualDevice( SalGraphics* pSGraphics,
+ long nDX, long nDY,
+ sal_uInt16 nBitCount,
+ const SystemGraphicsData* pData )
+{
+ WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics);
+
+ HDC hDC = NULL;
+ HBITMAP hBmp = NULL;
+ sal_Bool bOk = FALSE;
+
+ if( pData )
+ {
+ hDC = pData->hDC;
+ hBmp = NULL;
+ bOk = (hDC != NULL);
+ }
+ else
+ {
+ hDC = CreateCompatibleDC( pGraphics->mhDC );
+ if( !hDC )
+ ImplWriteLastError( GetLastError(), "CreateCompatibleDC in CreateVirtualDevice" );
+
+ hBmp = ImplCreateVirDevBitmap( pGraphics->mhDC,
+ nDX, nDY, nBitCount );
+ if( !hBmp )
+ ImplWriteLastError( GetLastError(), "ImplCreateVirDevBitmap in CreateVirtualDevice" );
+ // #124826# continue even if hBmp could not be created
+ // if we would return a failure in this case, the process
+ // would terminate which is not required
+
+ DBG_ASSERT( hBmp, "WinSalInstance::CreateVirtualDevice(), could not create Bitmap!" );
+
+ bOk = (hDC != NULL);
+ }
+
+ if ( bOk )
+ {
+ WinSalVirtualDevice* pVDev = new WinSalVirtualDevice;
+ SalData* pSalData = GetSalData();
+ WinSalGraphics* pVirGraphics = new WinSalGraphics;
+ pVirGraphics->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
+ pVirGraphics->mhDC = hDC;
+ pVirGraphics->mhWnd = 0;
+ pVirGraphics->mbPrinter = FALSE;
+ pVirGraphics->mbVirDev = TRUE;
+ pVirGraphics->mbWindow = FALSE;
+ pVirGraphics->mbScreen = pGraphics->mbScreen;
+ if ( pSalData->mhDitherPal && pVirGraphics->mbScreen )
+ {
+ pVirGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( pVirGraphics );
+
+ pVDev->mhDC = hDC;
+ pVDev->mhBmp = hBmp;
+ if( hBmp )
+ pVDev->mhDefBmp = SelectBitmap( hDC, hBmp );
+ else
+ pVDev->mhDefBmp = NULL;
+ pVDev->mpGraphics = pVirGraphics;
+ pVDev->mnBitCount = nBitCount;
+ pVDev->mbGraphics = FALSE;
+ pVDev->mbForeignDC = (pData != NULL);
+
+ // insert VirDev in VirDevList
+ pVDev->mpNext = pSalData->mpFirstVD;
+ pSalData->mpFirstVD = pVDev;
+
+ return pVDev;
+ }
+ else
+ {
+ if ( hDC && !pData )
+ DeleteDC( hDC );
+ if ( hBmp )
+ DeleteBitmap( hBmp );
+ return NULL;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalInstance::DestroyVirtualDevice( SalVirtualDevice* pDevice )
+{
+ delete pDevice;
+}
+
+// =======================================================================
+
+WinSalVirtualDevice::WinSalVirtualDevice()
+{
+ mhDC = (HDC) NULL; // HDC or 0 for Cache Device
+ mhBmp = (HBITMAP) NULL; // Memory Bitmap
+ mhDefBmp = (HBITMAP) NULL; // Default Bitmap
+ mpGraphics = NULL; // current VirDev graphics
+ mpNext = NULL; // next VirDev
+ mnBitCount = 0; // BitCount (0 or 1)
+ mbGraphics = FALSE; // is Graphics used
+ mbForeignDC = FALSE; // uses a foreign DC instead of a bitmap
+}
+
+// -----------------------------------------------------------------------
+
+WinSalVirtualDevice::~WinSalVirtualDevice()
+{
+ // remove VirDev from list of virtual devices
+ SalData* pSalData = GetSalData();
+ WinSalVirtualDevice** ppVirDev = &pSalData->mpFirstVD;
+ for(; (*ppVirDev != this) && *ppVirDev; ppVirDev = &(*ppVirDev)->mpNext );
+ if( *ppVirDev )
+ *ppVirDev = mpNext;
+
+ // destroy saved DC
+ if( mpGraphics->mhDefPal )
+ SelectPalette( mpGraphics->mhDC, mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics );
+ if( mhDefBmp )
+ SelectBitmap( mpGraphics->mhDC, mhDefBmp );
+ if( !mbForeignDC )
+ DeleteDC( mpGraphics->mhDC );
+ if( mhBmp )
+ DeleteBitmap( mhBmp );
+ delete mpGraphics;
+ mpGraphics = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalVirtualDevice::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ if ( mpGraphics )
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalVirtualDevice::ReleaseGraphics( SalGraphics* )
+{
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalVirtualDevice::SetSize( long nDX, long nDY )
+{
+ if( mbForeignDC || !mhBmp )
+ return TRUE; // ???
+ else
+ {
+ HBITMAP hNewBmp = ImplCreateVirDevBitmap( mhDC, nDX, nDY,
+ mnBitCount );
+ if ( hNewBmp )
+ {
+ SelectBitmap( mhDC, hNewBmp );
+ DeleteBitmap( mhBmp );
+ mhBmp = hNewBmp;
+ return TRUE;
+ }
+ else
+ {
+ ImplWriteLastError( GetLastError(), "ImplCreateVirDevBitmap in SetSize" );
+ return FALSE;
+ }
+ }
+}
+
+void WinSalVirtualDevice::GetSize( long& rWidth, long& rHeight )
+{
+ rWidth = GetDeviceCaps( mhDC, HORZRES );
+ rHeight= GetDeviceCaps( mhDC, VERTRES );
+}
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
new file mode 100755
index 000000000000..dd896059160e
--- /dev/null
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -0,0 +1,3186 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "rtl/ustring.hxx"
+
+#include "osl/module.h"
+#include "osl/file.h"
+
+#include "tools/svwin.h"
+
+#include "vcl/svapp.hxx"
+
+#include "win/salgdi.h"
+#include "win/saldata.hxx"
+
+// for GetMirroredChar
+#include "sft.hxx"
+#include "sallayout.hxx"
+
+#include <cstdio>
+#include <malloc.h>
+#ifndef __MINGW32__
+#define alloca _alloca
+#endif
+
+#ifdef GCP_KERN_HACK
+ #include <algorithm>
+#endif // GCP_KERN_HACK
+
+
+#define USE_UNISCRIBE
+#ifdef USE_UNISCRIBE
+#include <Usp10.h>
+#include <ShLwApi.h>
+#include <winver.h>
+#endif // USE_UNISCRIBE
+
+#include <hash_map>
+#include <set>
+
+typedef std::hash_map<int,int> IntMap;
+typedef std::set<int> IntSet;
+
+// Graphite headers
+#ifdef ENABLE_GRAPHITE
+#include <i18npool/mslangid.hxx>
+#include <graphite/GrClient.h>
+#include <graphite/WinFont.h>
+#include <graphite/Segment.h>
+#include <graphite_layout.hxx>
+#include <graphite_cache.hxx>
+#include <graphite_features.hxx>
+#endif
+
+#define DROPPED_OUTGLYPH 0xFFFF
+
+using namespace rtl;
+
+// =======================================================================
+
+// win32 specific physical font instance
+class ImplWinFontEntry : public ImplFontEntry
+{
+public:
+ ImplWinFontEntry( ImplFontSelectData& );
+ ~ImplWinFontEntry();
+
+private:
+ // TODO: also add HFONT??? Watch out for issues with too many active fonts...
+
+#ifdef GCP_KERN_HACK
+public:
+ bool HasKernData() const;
+ void SetKernData( int, const KERNINGPAIR* );
+ int GetKerning( sal_Unicode, sal_Unicode ) const;
+private:
+ KERNINGPAIR* mpKerningPairs;
+ int mnKerningPairs;
+#endif // GCP_KERN_HACK
+
+#ifdef USE_UNISCRIBE
+public:
+ SCRIPT_CACHE& GetScriptCache() const
+ { return maScriptCache; }
+private:
+ mutable SCRIPT_CACHE maScriptCache;
+#endif // USE_UNISCRIBE
+
+public:
+ int GetCachedGlyphWidth( int nCharCode ) const;
+ void CacheGlyphWidth( int nCharCode, int nCharWidth );
+
+ bool InitKashidaHandling( HDC );
+ int GetMinKashidaWidth() const { return mnMinKashidaWidth; }
+ int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
+
+private:
+ IntMap maWidthMap;
+ mutable int mnMinKashidaWidth;
+ mutable int mnMinKashidaGlyph;
+};
+
+// -----------------------------------------------------------------------
+
+inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
+{
+ maWidthMap[ nCharCode ] = nCharWidth;
+}
+
+inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
+{
+ IntMap::const_iterator it = maWidthMap.find( nCharCode );
+ if( it == maWidthMap.end() )
+ return -1;
+ return it->second;
+}
+
+// =======================================================================
+
+class WinLayout : public SalLayout
+{
+public:
+ WinLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
+ virtual void InitFont() const;
+ void SetFontScale( float f ) { mfFontScale = f; }
+ float GetFontScale() const { return mfFontScale; }
+ HFONT DisableFontScaling( void) const;
+
+#ifdef USE_UNISCRIBE
+ SCRIPT_CACHE& GetScriptCache() const
+ { return mrWinFontEntry.GetScriptCache(); }
+#endif // USE_UNISCRIBE
+
+protected:
+ HDC mhDC; // WIN32 device handle
+ HFONT mhFont; // WIN32 font handle
+ int mnBaseAdv; // x-offset relative to Layout origin
+ float mfFontScale; // allows metrics emulation of huge font sizes
+
+ const ImplWinFontData& mrWinFontData;
+ ImplWinFontEntry& mrWinFontEntry;
+};
+
+// =======================================================================
+
+class SimpleWinLayout : public WinLayout
+{
+public:
+ SimpleWinLayout( HDC, BYTE nCharSet, const ImplWinFontData&, ImplWinFontEntry& );
+ virtual ~SimpleWinLayout();
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+
+protected:
+ void Justify( long nNewWidth );
+ void ApplyDXArray( const ImplLayoutArgs& );
+
+private:
+ int mnGlyphCount;
+ int mnCharCount;
+ WCHAR* mpOutGlyphs;
+ int* mpGlyphAdvances; // if possible this is shared with mpGlyphAdvances[]
+ int* mpGlyphOrigAdvs;
+ int* mpCharWidths; // map rel char pos to char width
+ int* mpChars2Glyphs; // map rel char pos to abs glyph pos
+ int* mpGlyphs2Chars; // map abs glyph pos to abs char pos
+ bool* mpGlyphRTLFlags; // BiDi status for glyphs: true=>RTL
+ mutable long mnWidth;
+ bool mbDisableGlyphs;
+
+ int mnNotdefWidth;
+ BYTE mnCharSet;
+};
+
+// =======================================================================
+
+WinLayout::WinLayout( HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE )
+: mhDC( hDC ),
+ mhFont( (HFONT)::GetCurrentObject(hDC,OBJ_FONT) ),
+ mnBaseAdv( 0 ),
+ mfFontScale( 1.0 ),
+ mrWinFontData( rWFD ),
+ mrWinFontEntry( rWFE )
+{}
+
+// -----------------------------------------------------------------------
+
+void WinLayout::InitFont() const
+{
+ ::SelectObject( mhDC, mhFont );
+}
+
+// -----------------------------------------------------------------------
+
+// Using reasonably sized fonts to emulate huge fonts works around
+// a lot of problems in printer and display drivers. Huge fonts are
+// mostly used by high resolution reference devices which are never
+// painted to anyway. In the rare case that a huge font needs to be
+// displayed somewhere then the workaround doesn't help anymore.
+// If the drivers fail silently for huge fonts, so be it...
+HFONT WinLayout::DisableFontScaling() const
+{
+ if( mfFontScale == 1.0 )
+ return 0;
+
+ LOGFONTW aLogFont;
+ ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
+ aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight);
+ aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth);
+ HFONT hHugeFont = ::CreateFontIndirectW( &aLogFont);
+ if( !hHugeFont )
+ return 0;
+
+ return SelectFont( mhDC, hHugeFont );
+}
+
+// =======================================================================
+
+SimpleWinLayout::SimpleWinLayout( HDC hDC, BYTE nCharSet,
+ const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
+: WinLayout( hDC, rWinFontData, rWinFontEntry ),
+ mnGlyphCount( 0 ),
+ mnCharCount( 0 ),
+ mpOutGlyphs( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpGlyphOrigAdvs( NULL ),
+ mpCharWidths( NULL ),
+ mpChars2Glyphs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mpGlyphRTLFlags( NULL ),
+ mnWidth( 0 ),
+ mnNotdefWidth( -1 ),
+ mnCharSet( nCharSet ),
+ mbDisableGlyphs( false )
+{
+ mbDisableGlyphs = true;
+}
+
+// -----------------------------------------------------------------------
+
+SimpleWinLayout::~SimpleWinLayout()
+{
+ delete[] mpGlyphRTLFlags;
+ delete[] mpGlyphs2Chars;
+ delete[] mpChars2Glyphs;
+ if( mpCharWidths != mpGlyphAdvances )
+ delete[] mpCharWidths;
+ delete[] mpGlyphOrigAdvs;
+ delete[] mpGlyphAdvances;
+ delete[] mpOutGlyphs;
+}
+
+// -----------------------------------------------------------------------
+
+bool SimpleWinLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ // prepare layout
+ // TODO: fix case when recyclying old SimpleWinLayout object
+ mbDisableGlyphs |= ((rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) != 0);
+ mnCharCount = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+
+ if( !mbDisableGlyphs )
+ {
+ // Win32 glyph APIs have serious problems with vertical layout
+ // => workaround is to use the unicode methods then
+ if( rArgs.mnFlags & SAL_LAYOUT_VERTICAL )
+ mbDisableGlyphs = true;
+ else
+ // use cached value from font face
+ mbDisableGlyphs = mrWinFontData.IsGlyphApiDisabled();
+ }
+
+ // TODO: use a cached value for bDisableAsianKern from upper layers
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ TEXTMETRICA aTextMetricA;
+ if( ::GetTextMetricsA( mhDC, &aTextMetricA )
+ && !(aTextMetricA.tmPitchAndFamily & TMPF_FIXED_PITCH) && !(aTextMetricA.tmCharSet == 0x86) )
+ rArgs.mnFlags &= ~SAL_LAYOUT_KERNING_ASIAN;
+ }
+
+ // layout text
+ int i, j;
+
+ mnGlyphCount = 0;
+ bool bVertical = (rArgs.mnFlags & SAL_LAYOUT_VERTICAL) != 0;
+
+ // count the number of chars to process if no RTL run
+ rArgs.ResetPos();
+ bool bHasRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bHasRTL ) && !bHasRTL )
+ mnGlyphCount += j - i;
+
+ // if there are RTL runs we need room to remember individual BiDi flags
+ if( bHasRTL )
+ {
+ mpGlyphRTLFlags = new bool[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpGlyphRTLFlags[i] = false;
+ }
+
+ // rewrite the logical string if needed to prepare for the API calls
+ const sal_Unicode* pBidiStr = rArgs.mpStr + rArgs.mnMinCharPos;
+ if( (mnGlyphCount != mnCharCount) || bVertical )
+ {
+ // we need to rewrite the pBidiStr when any of
+ // - BiDirectional layout
+ // - vertical layout
+ // - partial runs (e.g. with control chars or for glyph fallback)
+ // are involved
+ sal_Unicode* pRewrittenStr = (sal_Unicode*)alloca( mnCharCount * sizeof(sal_Unicode) );
+ pBidiStr = pRewrittenStr;
+
+ // note: glyph to char mapping is relative to first character
+ mpChars2Glyphs = new int[ mnCharCount ];
+ mpGlyphs2Chars = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpChars2Glyphs[i] = mpGlyphs2Chars[i] = -1;
+
+ mnGlyphCount = 0;
+ rArgs.ResetPos();
+ bool bIsRTL = false;
+ while( rArgs.GetNextRun( &i, &j, &bIsRTL ) )
+ {
+ do
+ {
+ // get the next leftmost character in this run
+ int nCharPos = bIsRTL ? --j : i++;
+ sal_UCS4 cChar = rArgs.mpStr[ nCharPos ];
+
+ // in the RTL case mirror the character and remember its RTL status
+ if( bIsRTL )
+ {
+ cChar = ::GetMirroredChar( cChar );
+ mpGlyphRTLFlags[ mnGlyphCount ] = true;
+ }
+
+ // for vertical writing use vertical alternatives
+ if( bVertical )
+ {
+ sal_UCS4 cVert = ::GetVerticalChar( cChar );
+ if( cVert )
+ cChar = cVert;
+ }
+
+ // rewrite the original string
+ // update the mappings between original and rewritten string
+ // TODO: support surrogates in rewritten strings
+ pRewrittenStr[ mnGlyphCount ] = static_cast<sal_Unicode>(cChar);
+ mpGlyphs2Chars[ mnGlyphCount ] = nCharPos;
+ mpChars2Glyphs[ nCharPos - rArgs.mnMinCharPos ] = mnGlyphCount;
+ ++mnGlyphCount;
+ } while( i < j );
+ }
+ }
+
+ mpOutGlyphs = new WCHAR[ mnGlyphCount ];
+ mpGlyphAdvances = new int[ mnGlyphCount ];
+
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_PAIRS | SAL_LAYOUT_KERNING_ASIAN) )
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+
+#ifndef GCP_KERN_HACK
+ DWORD nGcpOption = 0;
+ // enable kerning if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ nGcpOption |= GCP_USEKERNING;
+#endif // GCP_KERN_HACK
+
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpOutGlyphs[i] = pBidiStr[ i ];
+ mnWidth = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ // get the current UCS-4 code point, check for surrogate pairs
+ const WCHAR* pCodes = reinterpret_cast<LPCWSTR>(&pBidiStr[i]);
+ unsigned nCharCode = pCodes[0];
+ bool bSurrogate = ((nCharCode >= 0xD800) && (nCharCode <= 0xDFFF));
+ if( bSurrogate )
+ {
+ if( nCharCode >= 0xDC00 ) // this part of a surrogate pair was already processed
+ continue;
+ nCharCode = 0x10000 + ((pCodes[0] - 0xD800) << 10) + (pCodes[1] - 0xDC00);
+ }
+
+ // get the advance width for the current UCS-4 code point
+ int nGlyphWidth = mrWinFontEntry.GetCachedGlyphWidth( nCharCode );
+ if( nGlyphWidth == -1 )
+ {
+ ABC aABC;
+ SIZE aExtent;
+ if( ::GetTextExtentPoint32W( mhDC, &pCodes[0], bSurrogate ? 2 : 1, &aExtent) )
+ nGlyphWidth = aExtent.cx;
+ else if( ::GetCharABCWidthsW( mhDC, nCharCode, nCharCode, &aABC ) )
+ nGlyphWidth = aABC.abcA + aABC.abcB + aABC.abcC;
+ else if( !::GetCharWidth32W( mhDC, nCharCode, nCharCode, &nGlyphWidth )
+ && !::GetCharWidthW( mhDC, nCharCode, nCharCode, &nGlyphWidth ) )
+ nGlyphWidth = 0;
+ mrWinFontEntry.CacheGlyphWidth( nCharCode, nGlyphWidth );
+ }
+ mpGlyphAdvances[ i ] = nGlyphWidth;
+ mnWidth += nGlyphWidth;
+
+ // remaining codes of surrogate pair get a zero width
+ if( bSurrogate && ((i+1) < mnGlyphCount) )
+ mpGlyphAdvances[ i+1 ] = 0;
+
+ // check with the font face if glyph fallback is needed
+ if( mrWinFontData.HasChar( nCharCode ) )
+ continue;
+
+ // request glyph fallback at this position in the string
+ bool bRTL = mpGlyphRTLFlags ? mpGlyphRTLFlags[i] : false;
+ int nCharPos = mpGlyphs2Chars ? mpGlyphs2Chars[i]: i + rArgs.mnMinCharPos;
+ rArgs.NeedFallback( nCharPos, bRTL );
+ if( bSurrogate && ((nCharPos+1) < rArgs.mnLength) )
+ rArgs.NeedFallback( nCharPos+1, bRTL );
+
+ // replace the current glyph shape with the NotDef glyph shape
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ {
+ // when we already are layouting for glyph fallback
+ // then a new unresolved glyph is not interesting
+ mnNotdefWidth = 0;
+ mpOutGlyphs[i] = DROPPED_OUTGLYPH;
+ }
+ else
+ {
+ if( mnNotdefWidth < 0 )
+ {
+ // get the width of the NotDef glyph
+ SIZE aExtent;
+ WCHAR cNotDef = rArgs.mpStr[ nCharPos ];
+ mnNotdefWidth = 0;
+ if( ::GetTextExtentPoint32W( mhDC, &cNotDef, 1, &aExtent) )
+ mnNotdefWidth = aExtent.cx;
+ }
+ // use a better NotDef glyph
+ if( !mbDisableGlyphs && !bSurrogate )
+ mpOutGlyphs[i] = 0;
+ }
+ if( bSurrogate && ((i+1) < mnGlyphCount) )
+ mpOutGlyphs[i+1] = DROPPED_OUTGLYPH;
+
+ // adjust the current glyph width to the NotDef glyph width
+ mnWidth += mnNotdefWidth - mpGlyphAdvances[i];
+ mpGlyphAdvances[i] = mnNotdefWidth;
+ if( mpGlyphOrigAdvs )
+ mpGlyphOrigAdvs[i] = mnNotdefWidth;
+ }
+
+#ifdef GCP_KERN_HACK
+ // apply kerning if the layout engine has not yet done it
+ if( rArgs.mnFlags & (SAL_LAYOUT_KERNING_ASIAN|SAL_LAYOUT_KERNING_PAIRS) )
+ {
+#else // GCP_KERN_HACK
+ // apply just asian kerning
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+ {
+ if( !(rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) )
+#endif // GCP_KERN_HACK
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[i] = mpGlyphAdvances[i];
+
+ // #99658# also apply asian kerning on the substring border
+ int nLen = mnGlyphCount;
+ if( rArgs.mnMinCharPos + nLen < rArgs.mnLength )
+ ++nLen;
+ for( i = 1; i < nLen; ++i )
+ {
+#ifdef GCP_KERN_HACK
+ if( rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS )
+ {
+ int nKernAmount = mrWinFontEntry.GetKerning( pBidiStr[i-1], pBidiStr[i] );
+ mpGlyphAdvances[ i-1 ] += nKernAmount;
+ mnWidth += nKernAmount;
+ }
+ else if( rArgs.mnFlags & SAL_LAYOUT_KERNING_ASIAN )
+#endif // GCP_KERN_HACK
+
+ if( ( (0x3000 == (0xFF00 & pBidiStr[i-1])) || (0x2010 == (0xFFF0 & pBidiStr[i-1])) || (0xFF00 == (0xFF00 & pBidiStr[i-1])))
+ && ( (0x3000 == (0xFF00 & pBidiStr[i])) || (0x2010 == (0xFFF0 & pBidiStr[i])) || (0xFF00 == (0xFF00 & pBidiStr[i])) ) )
+ {
+ long nKernFirst = +CalcAsianKerning( pBidiStr[i-1], true, bVertical );
+ long nKernNext = -CalcAsianKerning( pBidiStr[i], false, bVertical );
+
+ long nDelta = (nKernFirst < nKernNext) ? nKernFirst : nKernNext;
+ if( nDelta<0 && nKernFirst!=0 && nKernNext!=0 )
+ {
+ nDelta = (nDelta * mpGlyphAdvances[i-1] + 2) / 4;
+ mpGlyphAdvances[i-1] += nDelta;
+ mnWidth += nDelta;
+ }
+ }
+ }
+ }
+
+ // calculate virtual char widths
+ if( !mpGlyphs2Chars )
+ mpCharWidths = mpGlyphAdvances;
+ else
+ {
+ mpCharWidths = new int[ mnCharCount ];
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+
+ // scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
+ if( mfFontScale != 1.0 )
+ {
+ mnWidth = (long)(mnWidth * mfFontScale);
+ mnBaseAdv = (int)(mnBaseAdv * mfFontScale);
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
+ if( mpGlyphAdvances != mpCharWidths )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
+ if( mpGlyphOrigAdvs && (mpGlyphOrigAdvs != mpGlyphAdvances) )
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[i] = (int)(mpGlyphOrigAdvs[i] * mfFontScale);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int SimpleWinLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int& nStart,
+ long* pGlyphAdvances, int* pCharIndexes ) const
+{
+ // return zero if no more glyph found
+ if( nStart >= mnGlyphCount )
+ return 0;
+
+ // calculate glyph position relative to layout base
+ // TODO: avoid for nStart!=0 case by reusing rPos
+ long nXOffset = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+
+ // calculate absolute position in pixel units
+ Point aRelativePos( nXOffset, 0 );
+ rPos = GetDrawPosition( aRelativePos );
+
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ // update return values {nGlyphIndex,nCharPos,nGlyphAdvance}
+ sal_GlyphId nGlyphIndex = mpOutGlyphs[ nStart ];
+ if( mbDisableGlyphs )
+ {
+ if( mnLayoutFlags & SAL_LAYOUT_VERTICAL )
+ {
+ const sal_UCS4 cChar = static_cast<sal_UCS4>(nGlyphIndex & GF_IDXMASK);
+ if( mrWinFontData.HasGSUBstitutions( mhDC )
+ && mrWinFontData.IsGSUBstituted( cChar ) )
+ nGlyphIndex |= GF_GSUB | GF_ROTL;
+ else
+ {
+ nGlyphIndex |= GetVerticalFlags( cChar );
+ if( (nGlyphIndex & GF_ROTMASK) == 0 )
+ nGlyphIndex |= GF_VERT;
+ }
+ }
+ nGlyphIndex |= GF_ISCHAR;
+ }
+ ++nCount;
+ *(pGlyphs++) = nGlyphIndex;
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = mpGlyphAdvances[ nStart ];
+ if( pCharIndexes )
+ {
+ int nCharPos;
+ if( !mpGlyphs2Chars )
+ nCharPos = nStart + mnMinCharPos;
+ else
+ nCharPos = mpGlyphs2Chars[nStart];
+ *(pCharIndexes++) = nCharPos;
+ }
+
+ // stop at last glyph
+ if( ++nStart >= mnGlyphCount )
+ break;
+
+ // stop when next x-position is unexpected
+ if( !pGlyphAdvances && mpGlyphOrigAdvs )
+ if( mpGlyphAdvances[nStart-1] != mpGlyphOrigAdvs[nStart-1] )
+ break;
+ }
+
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::DrawText( SalGraphics& rGraphics ) const
+{
+ if( mnGlyphCount <= 0 )
+ return;
+
+ WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
+ HDC aHDC = rWinGraphics.mhDC;
+
+ HFONT hOrigFont = DisableFontScaling();
+
+ UINT mnDrawOptions = ETO_GLYPH_INDEX;
+ if( mbDisableGlyphs )
+ mnDrawOptions = 0;
+
+ Point aPos = GetDrawPosition( Point( mnBaseAdv, 0 ) );
+
+ // #108267#, break up into glyph portions of a limited size required by Win32 API
+ const unsigned int maxGlyphCount = 8192;
+ UINT numGlyphPortions = mnGlyphCount / maxGlyphCount;
+ UINT remainingGlyphs = mnGlyphCount % maxGlyphCount;
+
+ if( numGlyphPortions )
+ {
+ // #108267#,#109387# break up string into smaller chunks
+ // the output positions will be updated by windows (SetTextAlign)
+ POINT oldPos;
+ UINT oldTa = ::GetTextAlign( aHDC );
+ ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP );
+ ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos );
+ unsigned int i = 0;
+ for( unsigned int n = 0; n < numGlyphPortions; ++n, i+=maxGlyphCount )
+ ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
+ mpOutGlyphs+i, maxGlyphCount, mpGlyphAdvances+i );
+ ::ExtTextOutW( aHDC, 0, 0, mnDrawOptions, NULL,
+ mpOutGlyphs+i, remainingGlyphs, mpGlyphAdvances+i );
+ ::MoveToEx( aHDC, oldPos.x, oldPos.y, (LPPOINT) NULL);
+ ::SetTextAlign( aHDC, oldTa );
+ }
+ else
+ ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), mnDrawOptions, NULL,
+ mpOutGlyphs, mnGlyphCount, mpGlyphAdvances );
+
+ if( hOrigFont )
+ DeleteFont( SelectFont( aHDC, hOrigFont ) );
+}
+
+// -----------------------------------------------------------------------
+
+long SimpleWinLayout::FillDXArray( long* pDXArray ) const
+{
+ if( !mnWidth )
+ {
+ long mnWidth = mnBaseAdv;
+ for( int i = 0; i < mnGlyphCount; ++i )
+ mnWidth += mpGlyphAdvances[ i ];
+ }
+
+ if( pDXArray != NULL )
+ {
+ for( int i = 0; i < mnCharCount; ++i )
+ pDXArray[ i ] = mpCharWidths[ i ];
+ }
+
+ return mnWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int SimpleWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+// NOTE: the nFactor is used to prevent rounding errors for small nCharExtra values
+{
+ if( mnWidth )
+ if( (mnWidth * nFactor + mnCharCount * nCharExtra) <= nMaxWidth )
+ return STRING_LEN;
+
+ long nExtraWidth = mnBaseAdv * nFactor;
+ for( int n = 0; n < mnCharCount; ++n )
+ {
+ // skip unused characters
+ if( mpChars2Glyphs && (mpChars2Glyphs[n] < 0) )
+ continue;
+ // add char widths until max
+ nExtraWidth += mpCharWidths[ n ] * nFactor;
+ if( nExtraWidth >= nMaxWidth )
+ return (mnMinCharPos + n);
+ nExtraWidth += nCharExtra;
+ }
+
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
+{
+ long nXPos = mnBaseAdv;
+
+ if( !mpGlyphs2Chars )
+ {
+ for( int i = 0; i < nMaxIdx; i += 2 )
+ {
+ pCaretXArray[ i ] = nXPos;
+ nXPos += mpGlyphAdvances[ i>>1 ];
+ pCaretXArray[ i+1 ] = nXPos;
+ }
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < nMaxIdx; ++i )
+ pCaretXArray[ i ] = -1;
+
+ // assign glyph positions to character positions
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int nCurrIdx = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ long nXRight = nXPos + mpCharWidths[ nCurrIdx ];
+ nCurrIdx *= 2;
+ if( !(mpGlyphRTLFlags && mpGlyphRTLFlags[i]) )
+ {
+ // normal positions for LTR case
+ pCaretXArray[ nCurrIdx ] = nXPos;
+ pCaretXArray[ nCurrIdx+1 ] = nXRight;
+ }
+ else
+ {
+ // reverse positions for RTL case
+ pCaretXArray[ nCurrIdx ] = nXRight;
+ pCaretXArray[ nCurrIdx+1 ] = nXPos;
+ }
+ nXPos += mpGlyphAdvances[ i ];
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::Justify( long nNewWidth )
+{
+ long nOldWidth = mnWidth;
+ mnWidth = nNewWidth;
+
+ if( mnGlyphCount <= 0 )
+ return;
+
+ if( nNewWidth == nOldWidth )
+ return;
+
+ // the rightmost glyph cannot be stretched
+ const int nRight = mnGlyphCount - 1;
+ nOldWidth -= mpGlyphAdvances[ nRight ];
+ nNewWidth -= mpGlyphAdvances[ nRight ];
+
+ // count stretchable glyphs
+ int nStretchable = 0, i;
+ for( i = 0; i < nRight; ++i )
+ if( mpGlyphAdvances[i] >= 0 )
+ ++nStretchable;
+
+ // stretch these glyphs
+ int nDiffWidth = nNewWidth - nOldWidth;
+ for( i = 0; (i < nRight) && (nStretchable > 0); ++i )
+ {
+ if( mpGlyphAdvances[i] <= 0 )
+ continue;
+ int nDeltaWidth = nDiffWidth / nStretchable;
+ mpGlyphAdvances[i] += nDeltaWidth;
+ --nStretchable;
+ nDiffWidth -= nDeltaWidth;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ // adjust positions if requested
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+ else
+ return;
+
+ // recalculate virtual char widths if they were changed
+ if( mpCharWidths != mpGlyphAdvances )
+ {
+ int i;
+ if( !mpGlyphs2Chars )
+ {
+ // standard LTR case
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpCharWidths[ i ] = mpGlyphAdvances[ i ];
+ }
+ else
+ {
+ // BiDi or complex case
+ for( i = 0; i < mnCharCount; ++i )
+ mpCharWidths[ i ] = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ int j = mpGlyphs2Chars[ i ] - rArgs.mnMinCharPos;
+ if( j >= 0 )
+ mpCharWidths[ j ] += mpGlyphAdvances[ i ];
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
+{
+ // try to avoid disturbance of text flow for LSB rounding case;
+ const long* pDXArray = rArgs.mpDXArray;
+
+ int i = 0;
+ long nOldWidth = mnBaseAdv;
+ for(; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ {
+ nOldWidth += mpGlyphAdvances[ j ];
+ int nDiff = nOldWidth - pDXArray[ i ];
+
+ // disabled because of #104768#
+ // works great for static text, but problems when typing
+ // if( nDiff>+1 || nDiff<-1 )
+ // only bother with changing anything when something moved
+ if( nDiff != 0 )
+ break;
+ }
+ }
+ if( i >= mnCharCount )
+ return;
+
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphOrigAdvs[ i ] = mpGlyphAdvances[ i ];
+ }
+
+ mnWidth = mnBaseAdv;
+ for( i = 0; i < mnCharCount; ++i )
+ {
+ int j = !mpChars2Glyphs ? i : mpChars2Glyphs[i];
+ if( j >= 0 )
+ mpGlyphAdvances[j] = pDXArray[i] - mnWidth;
+ mnWidth = pDXArray[i];
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::MoveGlyph( int nStart, long nNewXPos )
+{
+ if( nStart > mnGlyphCount )
+ return;
+
+ // calculate the current x-position of the requested glyph
+ // TODO: cache absolute positions
+ int nXPos = mnBaseAdv;
+ for( int i = 0; i < nStart; ++i )
+ nXPos += mpGlyphAdvances[i];
+
+ // calculate the difference to the current glyph position
+ int nDelta = nNewXPos - nXPos;
+
+ // adjust the width of the layout if it was already cached
+ if( mnWidth )
+ mnWidth += nDelta;
+
+ // depending on whether the requested glyph is leftmost in the layout
+ // adjust either the layout's or the requested glyph's relative position
+ if( nStart > 0 )
+ mpGlyphAdvances[ nStart-1 ] += nDelta;
+ else
+ mnBaseAdv += nDelta;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::DropGlyph( int nStart )
+{
+ mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+}
+
+// -----------------------------------------------------------------------
+
+void SimpleWinLayout::Simplify( bool /*bIsBase*/ )
+{
+ // return early if no glyph has been dropped
+ int i = mnGlyphCount;
+ while( (--i >= 0) && (mpOutGlyphs[ i ] != DROPPED_OUTGLYPH) );
+ if( i < 0 )
+ return;
+
+ // convert the layout to a sparse layout if it is not already
+ if( !mpGlyphs2Chars )
+ {
+ mpGlyphs2Chars = new int[ mnGlyphCount ];
+ mpCharWidths = new int[ mnCharCount ];
+ // assertion: mnGlyphCount == mnCharCount
+ for( int k = 0; k < mnGlyphCount; ++k )
+ {
+ mpGlyphs2Chars[ k ] = mnMinCharPos + k;
+ mpCharWidths[ k ] = mpGlyphAdvances[ k ];
+ }
+ }
+
+ // remove dropped glyphs that are rightmost in the layout
+ for( i = mnGlyphCount; --i >= 0; )
+ {
+ if( mpOutGlyphs[ i ] != DROPPED_OUTGLYPH )
+ break;
+ if( mnWidth )
+ mnWidth -= mpGlyphAdvances[ i ];
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ mnGlyphCount = i + 1;
+
+ // keep original glyph widths around
+ if( !mpGlyphOrigAdvs )
+ {
+ mpGlyphOrigAdvs = new int[ mnGlyphCount ];
+ for( int k = 0; k < mnGlyphCount; ++k )
+ mpGlyphOrigAdvs[ k ] = mpGlyphAdvances[ k ];
+ }
+
+ // remove dropped glyphs inside the layout
+ int nNewGC = 0;
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ if( mpOutGlyphs[ i ] == DROPPED_OUTGLYPH )
+ {
+ // adjust relative position to last valid glyph
+ int nDroppedWidth = mpGlyphAdvances[ i ];
+ mpGlyphAdvances[ i ] = 0;
+ if( nNewGC > 0 )
+ mpGlyphAdvances[ nNewGC-1 ] += nDroppedWidth;
+ else
+ mnBaseAdv += nDroppedWidth;
+
+ // zero the virtual char width for the char that has a fallback
+ int nRelCharPos = mpGlyphs2Chars[ i ] - mnMinCharPos;
+ if( nRelCharPos >= 0 )
+ mpCharWidths[ nRelCharPos ] = 0;
+ }
+ else
+ {
+ if( nNewGC != i )
+ {
+ // rearrange the glyph array to get rid of the dropped glyph
+ mpOutGlyphs[ nNewGC ] = mpOutGlyphs[ i ];
+ mpGlyphAdvances[ nNewGC ] = mpGlyphAdvances[ i ];
+ mpGlyphOrigAdvs[ nNewGC ] = mpGlyphOrigAdvs[ i ];
+ mpGlyphs2Chars[ nNewGC ] = mpGlyphs2Chars[ i ];
+ }
+ ++nNewGC;
+ }
+ }
+
+ mnGlyphCount = nNewGC;
+ if( mnGlyphCount <= 0 )
+ mnWidth = mnBaseAdv = 0;
+}
+
+// =======================================================================
+
+#ifdef USE_UNISCRIBE
+
+struct VisualItem
+{
+public:
+ SCRIPT_ITEM* mpScriptItem;
+ int mnMinGlyphPos;
+ int mnEndGlyphPos;
+ int mnMinCharPos;
+ int mnEndCharPos;
+ //long mnPixelWidth;
+ int mnXOffset;
+ ABC maABCWidths;
+ bool mbHasKashidas;
+
+public:
+ bool IsEmpty() const { return (mnEndGlyphPos <= 0); }
+ bool IsRTL() const { return mpScriptItem->a.fRTL; }
+ bool HasKashidas() const { return mbHasKashidas; }
+};
+
+// -----------------------------------------------------------------------
+
+class UniscribeLayout : public WinLayout
+{
+public:
+ UniscribeLayout( HDC, const ImplWinFontData&, ImplWinFontEntry& );
+
+ virtual bool LayoutText( ImplLayoutArgs& );
+ virtual void AdjustLayout( ImplLayoutArgs& );
+ virtual void DrawText( SalGraphics& ) const;
+ virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+ sal_Int32* pGlyphAdvances, int* pCharPosAry ) const;
+
+ virtual long FillDXArray( long* pDXArray ) const;
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+ virtual bool IsKashidaPosValid ( int nCharPos ) const;
+
+ // for glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+ virtual void DisableGlyphInjection( bool bDisable ) { mbDisableGlyphInjection = bDisable; }
+
+protected:
+ virtual ~UniscribeLayout();
+
+ void Justify( long nNewWidth );
+ void ApplyDXArray( const ImplLayoutArgs& );
+
+ bool GetItemSubrange( const VisualItem&,
+ int& rMinIndex, int& rEndIndex ) const;
+
+private:
+ // item specific info
+ SCRIPT_ITEM* mpScriptItems; // in logical order
+ VisualItem* mpVisualItems; // in visual order
+ int mnItemCount; // number of visual items
+
+ // string specific info
+ // everything is in logical order
+ int mnCharCapacity;
+ WORD* mpLogClusters; // map from absolute_char_pos to relative_glyph_pos
+ int* mpCharWidths; // map from absolute_char_pos to char_width
+ int mnSubStringMin; // char_pos of first char in context
+
+ // glyph specific info
+ // everything is in visual order
+ int mnGlyphCount;
+ int mnGlyphCapacity;
+ int* mpGlyphAdvances; // glyph advance width before justification
+ int* mpJustifications; // glyph advance width after justification
+ WORD* mpOutGlyphs; // glyphids in visual order
+ GOFFSET* mpGlyphOffsets; // glyph offsets to the "naive" layout
+ SCRIPT_VISATTR* mpVisualAttrs; // glyph visual attributes
+ mutable int* mpGlyphs2Chars; // map from absolute_glyph_pos to absolute_char_pos
+
+ // kashida stuff
+ void InitKashidaHandling();
+ void KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos );
+ bool KashidaWordFix( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos );
+
+ int mnMinKashidaWidth;
+ int mnMinKashidaGlyph;
+ bool mbDisableGlyphInjection;
+};
+
+// -----------------------------------------------------------------------
+// dynamic loading of usp library
+
+static oslModule aUspModule = NULL;
+static bool bUspEnabled = true;
+
+static HRESULT ((WINAPI *pScriptIsComplex)( const WCHAR*, int, DWORD ));
+static HRESULT ((WINAPI *pScriptItemize)( const WCHAR*, int, int,
+ const SCRIPT_CONTROL*, const SCRIPT_STATE*, SCRIPT_ITEM*, int* ));
+static HRESULT ((WINAPI *pScriptShape)( HDC, SCRIPT_CACHE*, const WCHAR*,
+ int, int, SCRIPT_ANALYSIS*, WORD*, WORD*, SCRIPT_VISATTR*, int* ));
+static HRESULT ((WINAPI *pScriptPlace)( HDC, SCRIPT_CACHE*, const WORD*, int,
+ const SCRIPT_VISATTR*, SCRIPT_ANALYSIS*, int*, GOFFSET*, ABC* ));
+static HRESULT ((WINAPI *pScriptGetLogicalWidths)( const SCRIPT_ANALYSIS*,
+ int, int, const int*, const WORD*, const SCRIPT_VISATTR*, int* ));
+static HRESULT ((WINAPI *pScriptApplyLogicalWidth)( const int*, int, int, const WORD*,
+ const SCRIPT_VISATTR*, const int*, const SCRIPT_ANALYSIS*, ABC*, int* ));
+static HRESULT ((WINAPI *pScriptJustify)( const SCRIPT_VISATTR*,
+ const int*, int, int, int, int* ));
+static HRESULT ((WINAPI *pScriptTextOut)( const HDC, SCRIPT_CACHE*,
+ int, int, UINT, const RECT*, const SCRIPT_ANALYSIS*, const WCHAR*,
+ int, const WORD*, int, const int*, const int*, const GOFFSET* ));
+static HRESULT ((WINAPI *pScriptGetFontProperties)( HDC, SCRIPT_CACHE*, SCRIPT_FONTPROPERTIES* ));
+static HRESULT ((WINAPI *pScriptFreeCache)( SCRIPT_CACHE* ));
+
+static bool bManualCellAlign = true;
+
+// -----------------------------------------------------------------------
+
+static bool InitUSP()
+{
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "usp10" ) );
+ aUspModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ if( !aUspModule )
+ return (bUspEnabled = false);
+
+ pScriptIsComplex = (HRESULT (WINAPI*)(const WCHAR*,int,DWORD))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptIsComplex" );
+ bUspEnabled &= (NULL != pScriptIsComplex);
+
+ pScriptItemize = (HRESULT (WINAPI*)(const WCHAR*,int,int,
+ const SCRIPT_CONTROL*,const SCRIPT_STATE*,SCRIPT_ITEM*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptItemize" );
+ bUspEnabled &= (NULL != pScriptItemize);
+
+ pScriptShape = (HRESULT (WINAPI*)(HDC,SCRIPT_CACHE*,const WCHAR*,
+ int,int,SCRIPT_ANALYSIS*,WORD*,WORD*,SCRIPT_VISATTR*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptShape" );
+ bUspEnabled &= (NULL != pScriptShape);
+
+ pScriptPlace = (HRESULT (WINAPI*)(HDC, SCRIPT_CACHE*, const WORD*, int,
+ const SCRIPT_VISATTR*,SCRIPT_ANALYSIS*,int*,GOFFSET*,ABC*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptPlace" );
+ bUspEnabled &= (NULL != pScriptPlace);
+
+ pScriptGetLogicalWidths = (HRESULT (WINAPI*)(const SCRIPT_ANALYSIS*,
+ int,int,const int*,const WORD*,const SCRIPT_VISATTR*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetLogicalWidths" );
+ bUspEnabled &= (NULL != pScriptGetLogicalWidths);
+
+ pScriptApplyLogicalWidth = (HRESULT (WINAPI*)(const int*,int,int,const WORD*,
+ const SCRIPT_VISATTR*,const int*,const SCRIPT_ANALYSIS*,ABC*,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptApplyLogicalWidth" );
+ bUspEnabled &= (NULL != pScriptApplyLogicalWidth);
+
+ pScriptJustify = (HRESULT (WINAPI*)(const SCRIPT_VISATTR*,const int*,
+ int,int,int,int*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptJustify" );
+ bUspEnabled &= (NULL != pScriptJustify);
+
+ pScriptGetFontProperties = (HRESULT (WINAPI*)( HDC,SCRIPT_CACHE*,SCRIPT_FONTPROPERTIES*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptGetFontProperties" );
+ bUspEnabled &= (NULL != pScriptGetFontProperties);
+
+ pScriptTextOut = (HRESULT (WINAPI*)(const HDC,SCRIPT_CACHE*,
+ int,int,UINT,const RECT*,const SCRIPT_ANALYSIS*,const WCHAR*,
+ int,const WORD*,int,const int*,const int*,const GOFFSET*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptTextOut" );
+ bUspEnabled &= (NULL != pScriptTextOut);
+
+ pScriptFreeCache = (HRESULT (WINAPI*)(SCRIPT_CACHE*))
+ osl_getAsciiFunctionSymbol( aUspModule, "ScriptFreeCache" );
+ bUspEnabled &= (NULL != pScriptFreeCache);
+
+ if( !bUspEnabled )
+ {
+ osl_unloadModule( aUspModule );
+ aUspModule = NULL;
+ }
+
+ // get the DLL version info
+ int nUspVersion = 0;
+ // TODO: there must be a simpler way to get the friggin version info from OSL?
+ rtl_uString* pModuleURL = NULL;
+ osl_getModuleURLFromAddress( (void*)pScriptIsComplex, &pModuleURL );
+ rtl_uString* pModuleFileName = NULL;
+ if( pModuleURL )
+ osl_getSystemPathFromFileURL( pModuleURL, &pModuleFileName );
+ const sal_Unicode* pModuleFileCStr = NULL;
+ if( pModuleFileName )
+ pModuleFileCStr = rtl_uString_getStr( pModuleFileName );
+ if( pModuleFileCStr )
+ {
+ DWORD nHandle;
+ DWORD nBufSize = ::GetFileVersionInfoSizeW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), &nHandle );
+ char* pBuffer = (char*)alloca( nBufSize );
+ BOOL bRC = ::GetFileVersionInfoW( const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(pModuleFileCStr)), nHandle, nBufSize, pBuffer );
+ VS_FIXEDFILEINFO* pFixedFileInfo = NULL;
+ UINT nFixedFileSize = 0;
+ if( bRC )
+ ::VerQueryValueW( pBuffer, const_cast<LPWSTR>(L"\\"), (void**)&pFixedFileInfo, &nFixedFileSize );
+ if( pFixedFileInfo && pFixedFileInfo->dwSignature == 0xFEEF04BD )
+ nUspVersion = HIWORD(pFixedFileInfo->dwProductVersionMS) * 10000
+ + LOWORD(pFixedFileInfo->dwProductVersionMS);
+ }
+
+ // #i77976# USP>=1.0600 changed the need to manually align glyphs in their cells
+ if( nUspVersion >= 10600 )
+ bManualCellAlign = false;
+
+ return bUspEnabled;
+}
+
+// -----------------------------------------------------------------------
+
+UniscribeLayout::UniscribeLayout( HDC hDC,
+ const ImplWinFontData& rWinFontData, ImplWinFontEntry& rWinFontEntry )
+: WinLayout( hDC, rWinFontData, rWinFontEntry ),
+ mnItemCount( 0 ),
+ mpScriptItems( NULL ),
+ mpVisualItems( NULL ),
+ mpLogClusters( NULL ),
+ mpCharWidths( NULL ),
+ mnCharCapacity( 0 ),
+ mnSubStringMin( 0 ),
+ mnGlyphCapacity( 0 ),
+ mnGlyphCount( 0 ),
+ mpOutGlyphs( NULL ),
+ mpGlyphAdvances( NULL ),
+ mpJustifications( NULL ),
+ mpGlyphOffsets( NULL ),
+ mpVisualAttrs( NULL ),
+ mpGlyphs2Chars( NULL ),
+ mnMinKashidaGlyph( 0 ),
+ mbDisableGlyphInjection( false )
+{}
+
+// -----------------------------------------------------------------------
+
+UniscribeLayout::~UniscribeLayout()
+{
+ delete[] mpScriptItems;
+ delete[] mpVisualItems;
+ delete[] mpLogClusters;
+ delete[] mpCharWidths;
+ delete[] mpOutGlyphs;
+ delete[] mpGlyphAdvances;
+ delete[] mpJustifications;
+ delete[] mpGlyphOffsets;
+ delete[] mpVisualAttrs;
+ delete[] mpGlyphs2Chars;
+}
+
+// -----------------------------------------------------------------------
+
+bool UniscribeLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+ // for a base layout only the context glyphs have to be dropped
+ // => when the whole string is involved there is no extra context
+ typedef std::vector<int> TIntVector;
+ TIntVector aDropChars;
+ if( rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK )
+ {
+ // calculate superfluous context char positions
+ aDropChars.push_back( 0 );
+ aDropChars.push_back( rArgs.mnLength );
+ int nMin, nEnd;
+ bool bRTL;
+ for( rArgs.ResetPos(); rArgs.GetNextRun( &nMin, &nEnd, &bRTL ); )
+ {
+ aDropChars.push_back( nMin );
+ aDropChars.push_back( nEnd );
+ }
+ // prepare aDropChars for binary search which will allow to
+ // not bother with visual items that will be dropped anyway
+ std::sort( aDropChars.begin(), aDropChars.end() );
+ }
+
+ // prepare layout
+ // TODO: fix case when recyclying old UniscribeLayout object
+ mnMinCharPos = rArgs.mnMinCharPos;
+ mnEndCharPos = rArgs.mnEndCharPos;
+
+ // determine script items from string
+
+ // prepare itemization
+ // TODO: try to avoid itemization since it costs a lot of performance
+ SCRIPT_STATE aScriptState = {0,false,false,false,false,false,false,false,false,0,0};
+ aScriptState.uBidiLevel = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL));
+ aScriptState.fOverrideDirection = (0 != (rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG));
+ aScriptState.fDigitSubstitute = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
+ aScriptState.fArabicNumContext = aScriptState.fDigitSubstitute & aScriptState.uBidiLevel;
+ DWORD nLangId = 0; // TODO: get language from font
+ SCRIPT_CONTROL aScriptControl = {nLangId,false,false,false,false,false,false,false,false,0};
+ aScriptControl.fNeutralOverride = aScriptState.fOverrideDirection;
+ aScriptControl.fContextDigits = (0 != (rArgs.mnFlags & SAL_LAYOUT_SUBSTITUTE_DIGITS));
+ // determine relevant substring and work only on it
+ // when Bidi status is unknown we need to look at the whole string though
+ mnSubStringMin = 0;
+ int nSubStringEnd = rArgs.mnLength;
+ if( aScriptState.fOverrideDirection )
+ {
+ // TODO: limit substring to portion limits
+ mnSubStringMin = rArgs.mnMinCharPos - 8;
+ if( mnSubStringMin < 0 )
+ mnSubStringMin = 0;
+ nSubStringEnd = rArgs.mnEndCharPos + 8;
+ if( nSubStringEnd > rArgs.mnLength )
+ nSubStringEnd = rArgs.mnLength;
+
+ }
+
+ // now itemize the substring with its context
+ for( int nItemCapacity = 16;; nItemCapacity *= 8 )
+ {
+ mpScriptItems = new SCRIPT_ITEM[ nItemCapacity ];
+ HRESULT nRC = (*pScriptItemize)(
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + mnSubStringMin), nSubStringEnd - mnSubStringMin,
+ nItemCapacity - 1, &aScriptControl, &aScriptState,
+ mpScriptItems, &mnItemCount );
+ if( !nRC ) // break loop when everything is correctly itemized
+ break;
+
+ // prepare bigger buffers for another itemization round
+ delete[] mpScriptItems;
+ mpScriptItems = NULL;
+ if( nRC != E_OUTOFMEMORY )
+ return false;
+ if( nItemCapacity > (nSubStringEnd - mnSubStringMin) + 16 )
+ return false;
+ }
+
+ // calculate the order of visual items
+ int nItem, i;
+
+ // adjust char positions by substring offset
+ for( nItem = 0; nItem <= mnItemCount; ++nItem )
+ mpScriptItems[ nItem ].iCharPos += mnSubStringMin;
+ // default visual item ordering
+ mpVisualItems = new VisualItem[ mnItemCount ];
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // initialize char specific item info
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ SCRIPT_ITEM* pScriptItem = &mpScriptItems[ nItem ];
+ rVisualItem.mpScriptItem = pScriptItem;
+ rVisualItem.mnMinCharPos = pScriptItem[0].iCharPos;
+ rVisualItem.mnEndCharPos = pScriptItem[1].iCharPos;
+ }
+
+ // reorder visual item order if needed
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
+ {
+ // force RTL item ordering if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL )
+ {
+ VisualItem* pVI0 = &mpVisualItems[ 0 ];
+ VisualItem* pVI1 = &mpVisualItems[ mnItemCount ];
+ while( pVI0 < --pVI1 )
+ {
+ VisualItem aVtmp = *pVI0;
+ *(pVI0++) = *pVI1;
+ *pVI1 = aVtmp;
+ }
+ }
+ }
+ else if( mnItemCount > 1 )
+ {
+ // apply bidi algorithm's rule L2 on item level
+ // TODO: use faster L2 algorithm
+ int nMaxBidiLevel = 0;
+ VisualItem* pVI = &mpVisualItems[0];
+ VisualItem* const pVIend = pVI + mnItemCount;
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
+ nMaxBidiLevel = pVI->mpScriptItem->a.s.uBidiLevel;
+
+ while( --nMaxBidiLevel >= 0 )
+ {
+ for( pVI = &mpVisualItems[0]; pVI < pVIend; )
+ {
+ // find item range that needs reordering
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel < pVI->mpScriptItem->a.s.uBidiLevel )
+ break;
+ VisualItem* pVImin = pVI++;
+ for(; pVI < pVIend; ++pVI )
+ if( nMaxBidiLevel >= pVI->mpScriptItem->a.s.uBidiLevel )
+ break;
+ VisualItem* pVImax = pVI++;
+
+ // reverse order of items in this range
+ while( pVImin < --pVImax )
+ {
+ VisualItem aVtmp = *pVImin;
+ *(pVImin++) = *pVImax;
+ *pVImax = aVtmp;
+ }
+ }
+ }
+ }
+
+ // allocate arrays
+ // TODO: when reusing object reuse old allocations or delete them
+ // TODO: use only [nSubStringMin..nSubStringEnd) instead of [0..nSubStringEnd)
+ mnCharCapacity = nSubStringEnd;
+ mpLogClusters = new WORD[ mnCharCapacity ];
+ mpCharWidths = new int[ mnCharCapacity ];
+
+ mnGlyphCount = 0;
+ mnGlyphCapacity = 16 + 4 * (nSubStringEnd - mnSubStringMin); // worst case assumption
+ mpGlyphAdvances = new int[ mnGlyphCapacity ];
+ mpOutGlyphs = new WORD[ mnGlyphCapacity ];
+ mpGlyphOffsets = new GOFFSET[ mnGlyphCapacity ];
+ mpVisualAttrs = new SCRIPT_VISATTR[ mnGlyphCapacity ];
+
+ long nXOffset = 0;
+ for( int j = mnSubStringMin; j < nSubStringEnd; ++j )
+ mpCharWidths[j] = 0;
+
+ // layout script items
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // initialize glyph specific item info
+ rVisualItem.mnMinGlyphPos = mnGlyphCount;
+ rVisualItem.mnEndGlyphPos = 0;
+ rVisualItem.mnXOffset = nXOffset;
+ //rVisualItem.mnPixelWidth = 0;
+
+ // shortcut ignorable items
+ if( (rArgs.mnEndCharPos <= rVisualItem.mnMinCharPos)
+ || (rArgs.mnMinCharPos >= rVisualItem.mnEndCharPos) )
+ {
+ for( int i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
+ mpLogClusters[i] = sal::static_int_cast<WORD>(~0U);
+ continue;
+ }
+
+ // override bidi analysis if requested
+ if( rArgs.mnFlags & SAL_LAYOUT_BIDI_STRONG )
+ {
+ // FIXME: is this intended ?
+ rVisualItem.mpScriptItem->a.fRTL = (aScriptState.uBidiLevel & 1);
+ rVisualItem.mpScriptItem->a.s.uBidiLevel = aScriptState.uBidiLevel;
+ rVisualItem.mpScriptItem->a.s.fOverrideDirection = aScriptState.fOverrideDirection;
+ }
+
+ // convert the unicodes to glyphs
+ int nGlyphCount = 0;
+ int nCharCount = rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos;
+ HRESULT nRC = (*pScriptShape)( mhDC, &rScriptCache,
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
+ nCharCount,
+ mnGlyphCapacity - rVisualItem.mnMinGlyphPos, // problem when >0xFFFF
+ &rVisualItem.mpScriptItem->a,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &nGlyphCount );
+
+ // find and handle problems in the unicode to glyph conversion
+ if( nRC == USP_E_SCRIPT_NOT_IN_FONT )
+ {
+ // the whole visual item needs a fallback, but make sure that the next
+ // fallback request is limited to the characters in the original request
+ // => this is handled in ImplLayoutArgs::PrepareFallback()
+ rArgs.NeedFallback( rVisualItem.mnMinCharPos, rVisualItem.mnEndCharPos,
+ rVisualItem.IsRTL() );
+
+ // don't bother to do a default layout in a fallback level
+ if( 0 != (rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) )
+ continue;
+
+ // the primitive layout engine is good enough for the default layout
+ rVisualItem.mpScriptItem->a.eScript = SCRIPT_UNDEFINED;
+ nRC = (*pScriptShape)( mhDC, &rScriptCache,
+ reinterpret_cast<LPCWSTR>(rArgs.mpStr + rVisualItem.mnMinCharPos),
+ nCharCount,
+ mnGlyphCapacity - rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &nGlyphCount );
+
+ if( nRC != 0 )
+ continue;
+
+#if 0 // keep the glyphs for now because they are better than nothing
+ // mark as NotDef glyphs
+ for( i = 0; i < nGlyphCount; ++i )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 0;
+#endif
+ }
+ else if( nRC != 0 )
+ // something undefined happened => give up for this visual item
+ continue;
+ else // if( nRC == 0 )
+ {
+ // check if there are any NotDef glyphs
+ for( i = 0; i < nGlyphCount; ++i )
+ if( 0 == mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
+ break;
+ if( i < nGlyphCount )
+ {
+ // clip charpos limits to the layout string without context
+ int nMinCharPos = rVisualItem.mnMinCharPos;
+ if( nMinCharPos < rArgs.mnMinCharPos )
+ nMinCharPos = rArgs.mnMinCharPos;
+ int nEndCharPos = rVisualItem.mnEndCharPos;
+ if( nEndCharPos > rArgs.mnEndCharPos )
+ nEndCharPos = rArgs.mnEndCharPos;
+ // request fallback for individual NotDef glyphs
+ do
+ {
+ // ignore non-NotDef glyphs
+ if( 0 != mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] )
+ continue;
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = DROPPED_OUTGLYPH;
+ // request fallback for the whole cell that resulted in a NotDef glyph
+ // TODO: optimize algorithm
+ const bool bRTL = rVisualItem.IsRTL();
+ if( !bRTL )
+ {
+ // request fallback for the left-to-right cell
+ for( int c = nMinCharPos; c < nEndCharPos; ++c )
+ {
+ if( mpLogClusters[ c ] == i )
+ {
+ // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
+ if( rArgs.mpStr[ c ] == 0x2060 )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
+ else
+ // <--
+ rArgs.NeedFallback( c, false );
+ }
+ }
+ }
+ else
+ {
+ // request fallback for the right to left cell
+ for( int c = nEndCharPos; --c >= nMinCharPos; )
+ {
+ if( mpLogClusters[ c ] == i )
+ {
+ // --> HDU/FME 2005-10-25 #i55716# skip WORDJOINER
+ if( rArgs.mpStr[ c ] == 0x2060 )
+ mpOutGlyphs[ i + rVisualItem.mnMinGlyphPos ] = 1;
+ else
+ // <--
+ rArgs.NeedFallback( c, true );
+ }
+ }
+ }
+ } while( ++i < nGlyphCount );
+ }
+ }
+
+ // now place the glyphs
+ nRC = (*pScriptPlace)( mhDC, &rScriptCache,
+ mpOutGlyphs + rVisualItem.mnMinGlyphPos,
+ nGlyphCount,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ mpGlyphOffsets + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.maABCWidths );
+
+ if( nRC != 0 )
+ continue;
+
+ // calculate the logical char widths from the glyph layout
+ nRC = (*pScriptGetLogicalWidths)(
+ &rVisualItem.mpScriptItem->a,
+ nCharCount, nGlyphCount,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpCharWidths + rVisualItem.mnMinCharPos );
+
+ // update the glyph counters
+ mnGlyphCount += nGlyphCount;
+ rVisualItem.mnEndGlyphPos = mnGlyphCount;
+
+ // update nXOffset
+ int nEndGlyphPos;
+ if( GetItemSubrange( rVisualItem, i, nEndGlyphPos ) )
+ for(; i < nEndGlyphPos; ++i )
+ nXOffset += mpGlyphAdvances[ i ];
+
+ // TODO: shrink glyphpos limits to match charpos/fallback limits
+ //pVI->mnMinGlyphPos = nMinGlyphPos;
+ //pVI->mnEndGlyphPos = nEndGlyphPos;
+
+ // drop the superfluous context glyphs
+ TIntVector::const_iterator it = aDropChars.begin();
+ while( it != aDropChars.end() )
+ {
+ // find matching "drop range"
+ int nMinDropPos = *(it++); // begin of drop range
+ if( nMinDropPos >= rVisualItem.mnEndCharPos )
+ break;
+ int nEndDropPos = *(it++); // end of drop range
+ if( nEndDropPos <= rVisualItem.mnMinCharPos )
+ continue;
+ // clip "drop range" to visual item's char range
+ if( nMinDropPos <= rVisualItem.mnMinCharPos )
+ {
+ nMinDropPos = rVisualItem.mnMinCharPos;
+ // drop the whole visual item if possible
+ if( nEndDropPos >= rVisualItem.mnEndCharPos )
+ {
+ rVisualItem.mnEndGlyphPos = 0;
+ break;
+ }
+ }
+ if( nEndDropPos > rVisualItem.mnEndCharPos )
+ nEndDropPos = rVisualItem.mnEndCharPos;
+
+ // drop the glyphs which correspond to the charpos range
+ // drop the corresponding glyphs in the cluster
+ for( int c = nMinDropPos; c < nEndDropPos; ++c )
+ {
+ int nGlyphPos = mpLogClusters[c] + rVisualItem.mnMinGlyphPos;
+ // no need to bother when the cluster was already dropped
+ if( mpOutGlyphs[ nGlyphPos ] != DROPPED_OUTGLYPH )
+ {
+ for(;;)
+ {
+ mpOutGlyphs[ nGlyphPos ] = DROPPED_OUTGLYPH;
+ // until the end of visual item
+ if( ++nGlyphPos >= rVisualItem.mnEndGlyphPos )
+ break;
+ // until the next cluster start
+ if( mpVisualAttrs[ nGlyphPos ].fClusterStart )
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // scale layout metrics if needed
+ // TODO: does it make the code more simple if the metric scaling
+ // is moved to the methods that need metric scaling (e.g. FillDXArray())?
+ if( mfFontScale != 1.0 )
+ {
+ mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
+
+ for( i = 0; i < mnItemCount; ++i )
+ mpVisualItems[i].mnXOffset = (int)((double)mpVisualItems[i].mnXOffset*mfFontScale);
+
+ mnBaseAdv = (int)((double)mnBaseAdv*mfFontScale);
+ for( i = 0; i < mnGlyphCount; ++i )
+ {
+ mpGlyphAdvances[i] = (int)(mpGlyphAdvances[i] * mfFontScale);
+ mpGlyphOffsets[i].du = (LONG)(mpGlyphOffsets[i].du * mfFontScale);
+ mpGlyphOffsets[i].dv = (LONG)(mpGlyphOffsets[i].dv * mfFontScale);
+ // mpJustifications are still NULL
+ }
+
+ for( i = mnSubStringMin; i < nSubStringEnd; ++i )
+ mpCharWidths[i] = (int)(mpCharWidths[i] * mfFontScale);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+// calculate the range of relevant glyphs for this visual item
+bool UniscribeLayout::GetItemSubrange( const VisualItem& rVisualItem,
+ int& rMinGlyphPos, int& rEndGlyphPos ) const
+{
+ // return early when nothing of interest in this item
+ if( rVisualItem.IsEmpty()
+ || (rVisualItem.mnEndCharPos <= mnMinCharPos)
+ || (mnEndCharPos <= rVisualItem.mnMinCharPos) )
+ return false;
+
+ // default: subrange is complete range
+ rMinGlyphPos = rVisualItem.mnMinGlyphPos;
+ rEndGlyphPos = rVisualItem.mnEndGlyphPos;
+
+ // return early when the whole item is of interest
+ if( (mnMinCharPos <= rVisualItem.mnMinCharPos)
+ && (rVisualItem.mnEndCharPos <= mnEndCharPos ) )
+ return true;
+
+ // get glyph range from char range by looking at cluster boundries
+ // TODO: optimize for case that LTR/RTL correspond to monotonous glyph indexes
+ rMinGlyphPos = rVisualItem.mnEndGlyphPos;
+ int nMaxGlyphPos = 0;
+
+ int i = mnMinCharPos;
+ if( i < rVisualItem.mnMinCharPos )
+ i = rVisualItem.mnMinCharPos;
+ int nCharPosLimit = rVisualItem.mnEndCharPos;
+ if( nCharPosLimit > mnEndCharPos )
+ nCharPosLimit = mnEndCharPos;
+ for(; i < nCharPosLimit; ++i )
+ {
+ int n = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
+ if( rMinGlyphPos > n )
+ rMinGlyphPos = n;
+ if( nMaxGlyphPos < n )
+ nMaxGlyphPos = n;
+ }
+ if (nMaxGlyphPos > rVisualItem.mnEndGlyphPos)
+ nMaxGlyphPos = rVisualItem.mnEndGlyphPos - 1;
+
+ // extend the glyph range to account for all glyphs in referenced clusters
+ if( !rVisualItem.IsRTL() ) // LTR-item
+ {
+ // extend to rightmost glyph of rightmost referenced cluster
+ for( i = nMaxGlyphPos; ++i < rVisualItem.mnEndGlyphPos; nMaxGlyphPos = i )
+ if( mpVisualAttrs[i].fClusterStart )
+ break;
+ }
+ else // RTL-item
+ {
+ // extend to leftmost glyph of leftmost referenced cluster
+ for( i = rMinGlyphPos; --i >= rVisualItem.mnMinGlyphPos; rMinGlyphPos = i )
+ if( mpVisualAttrs[i].fClusterStart )
+ break;
+ }
+ rEndGlyphPos = nMaxGlyphPos + 1;
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos,
+ int& nStartx8, sal_Int32* pGlyphAdvances, int* pCharPosAry ) const
+{
+ // HACK to allow fake-glyph insertion (e.g. for kashidas)
+ // TODO: use iterator idiom instead of GetNextGlyphs(...)
+ // TODO: else make sure that the limit for glyph injection is sufficient (currently 256)
+ int nSubIter = nStartx8 & 0xff;
+ int nStart = nStartx8 >> 8;
+
+ // check the glyph iterator
+ if( nStart > mnGlyphCount ) // nStart>MAX means no more glyphs
+ return 0;
+
+ // find the visual item for the nStart glyph position
+ int nItem = 0;
+ const VisualItem* pVI = mpVisualItems;
+ if( nStart <= 0 ) // nStart<=0 requests the first visible glyph
+ {
+ // find first visible item
+ for(; nItem < mnItemCount; ++nItem, ++pVI )
+ if( !pVI->IsEmpty() )
+ break;
+ // it is possible that there are glyphs but no valid visual item
+ // TODO: get rid of these visual items more early
+ if( nItem < mnItemCount )
+ nStart = pVI->mnMinGlyphPos;
+ }
+ else //if( nStart > 0 ) // nStart>0 means absolute glyph pos +1
+ {
+ --nStart;
+
+ // find matching item
+ for(; nItem < mnItemCount; ++nItem, ++pVI )
+ if( (nStart >= pVI->mnMinGlyphPos)
+ && (nStart < pVI->mnEndGlyphPos) )
+ break;
+ }
+
+ // after the last visual item there are no more glyphs
+ if( (nItem >= mnItemCount) || (nStart < 0) )
+ {
+ nStartx8 = (mnGlyphCount + 1) << 8;
+ return 0;
+ }
+
+ // calculate the first glyph in the next visual item
+ int nNextItemStart = mnGlyphCount;
+ while( ++nItem < mnItemCount )
+ {
+ if( mpVisualItems[nItem].IsEmpty() )
+ continue;
+ nNextItemStart = mpVisualItems[nItem].mnMinGlyphPos;
+ break;
+ }
+
+ // get the range of relevant glyphs in this visual item
+ int nMinGlyphPos, nEndGlyphPos;
+ bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ DBG_ASSERT( bRC, "USPLayout::GNG GISR() returned false" );
+ if( !bRC )
+ {
+ nStartx8 = (mnGlyphCount + 1) << 8;
+ return 0;
+ }
+
+ // make sure nStart is inside the range of relevant glyphs
+ if( nStart < nMinGlyphPos )
+ nStart = nMinGlyphPos;
+
+ // calculate the start glyph xoffset relative to layout's base position,
+ // advance to next visual glyph position by using adjusted glyph widths
+ // TODO: speed up the calculation for nStart!=0 case by using rPos as a cache
+ long nXOffset = pVI->mnXOffset;
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int i = nMinGlyphPos; i < nStart; ++i )
+ nXOffset += pGlyphWidths[ i ];
+
+ // adjust the nXOffset relative to glyph cluster start
+ int c = mnMinCharPos;
+ if( !pVI->IsRTL() ) // LTR-case
+ {
+ // LTR case: subtract the remainder of the cell from xoffset
+ int nTmpIndex = mpLogClusters[c];
+ while( (--c >= pVI->mnMinCharPos)
+ && (nTmpIndex == mpLogClusters[c]) )
+ nXOffset -= mpCharWidths[c];
+ }
+ else // RTL-case
+ {
+ // RTL case: add the remainder of the cell from xoffset
+ int nTmpIndex = mpLogClusters[ pVI->mnEndCharPos - 1 ];
+ while( (--c >= pVI->mnMinCharPos)
+ && (nTmpIndex == mpLogClusters[c]) )
+ nXOffset += mpCharWidths[c];
+
+ // adjust the xoffset if justified glyphs are not positioned at their justified positions yet
+ if( mpJustifications && !bManualCellAlign )
+ nXOffset += mpJustifications[ nStart ] - mpGlyphAdvances[ nStart ];
+ }
+
+ // create mpGlyphs2Chars[] if it is needed later
+ if( pCharPosAry && !mpGlyphs2Chars )
+ {
+ // create and reset the new array
+ mpGlyphs2Chars = new int[ mnGlyphCapacity ];
+ for( int i = 0; i < mnGlyphCount; ++i )
+ mpGlyphs2Chars[i] = -1;
+ // calculate the char->glyph mapping
+ for( nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // ignore invisible visual items
+ const VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+ // calculate the mapping by using mpLogClusters[]
+ // mpGlyphs2Chars[] should obey the logical order
+ // => reversing the loop does this by overwriting higher logicals
+ for( c = rVI.mnEndCharPos; --c >= rVI.mnMinCharPos; )
+ {
+ int i = mpLogClusters[c] + rVI.mnMinGlyphPos;
+ mpGlyphs2Chars[i] = c;
+ }
+ }
+ }
+
+ // calculate the absolute position of the first result glyph in pixel units
+ const GOFFSET aGOffset = mpGlyphOffsets[ nStart ];
+ Point aRelativePos( nXOffset + aGOffset.du, -aGOffset.dv );
+ rPos = GetDrawPosition( aRelativePos );
+
+ // fill the result arrays
+ int nCount = 0;
+ while( nCount < nLen )
+ {
+ // prepare return values
+ sal_GlyphId aGlyphId = mpOutGlyphs[ nStart ];
+ int nGlyphWidth = pGlyphWidths[ nStart ];
+ int nCharPos = -1; // no need to determine charpos
+ if( mpGlyphs2Chars ) // unless explicitly requested+provided
+ nCharPos = mpGlyphs2Chars[ nStart ];
+
+ // inject kashida glyphs if needed
+ if( !mbDisableGlyphInjection
+ && mpJustifications
+ && mnMinKashidaWidth
+ && mpVisualAttrs[nStart].uJustification >= SCRIPT_JUSTIFY_ARABIC_NORMAL )
+ {
+ // prepare draw position adjustment
+ int nExtraOfs = (nSubIter++) * mnMinKashidaWidth;
+ // calculate space available for the injected glyphs
+ nGlyphWidth = mpGlyphAdvances[ nStart ];
+ const int nExtraWidth = mpJustifications[ nStart ] - nGlyphWidth;
+ const int nToFillWidth = nExtraWidth - nExtraOfs;
+ if( (4*nToFillWidth >= mnMinKashidaWidth) // prevent glyph-injection if there is no room
+ || ((nSubIter > 1) && (nToFillWidth > 0)) ) // unless they can overlap with others
+ {
+ // handle if there is not sufficient room for a full glyph
+ if( nToFillWidth < mnMinKashidaWidth )
+ {
+ // overlap it with the previously injected glyph if possible
+ int nOverlap = mnMinKashidaWidth - nToFillWidth;
+ // else overlap it with both neighboring glyphs
+ if( nSubIter <= 1 )
+ nOverlap /= 2;
+ nExtraOfs -= nOverlap;
+ }
+ nGlyphWidth = mnMinKashidaWidth;
+ aGlyphId = mnMinKashidaGlyph;
+ nCharPos = -1;
+ }
+ else
+ {
+ nExtraOfs += nToFillWidth; // at right of cell
+ nSubIter = 0; // done with glyph injection
+ }
+ if( !bManualCellAlign )
+ nExtraOfs -= nExtraWidth; // adjust for right-aligned cells
+
+ // adjust the draw position for the injected-glyphs case
+ if( nExtraOfs )
+ {
+ aRelativePos.X() += nExtraOfs;
+ rPos = GetDrawPosition( aRelativePos );
+ }
+ }
+
+ // update return values
+ *(pGlyphs++) = aGlyphId;
+ if( pGlyphAdvances )
+ *(pGlyphAdvances++) = nGlyphWidth;
+ if( pCharPosAry )
+ *(pCharPosAry++) = nCharPos;
+
+ // increment counter of returned glyphs
+ ++nCount;
+
+ // reduce code complexity by returning early in glyph-injection case
+ if( nSubIter != 0 )
+ break;
+
+ // stop after the last visible glyph in this visual item
+ if( ++nStart >= nEndGlyphPos )
+ {
+ nStart = nNextItemStart;
+ break;
+ }
+
+ // RTL-justified glyph positioning is not easy
+ // simplify the code by just returning only one glyph at a time
+ if( mpJustifications && pVI->IsRTL() )
+ break;
+
+ // stop when the x-position of the next glyph is unexpected
+ if( !pGlyphAdvances )
+ if( (mpGlyphOffsets && (mpGlyphOffsets[nStart].du != aGOffset.du) )
+ || (mpJustifications && (mpJustifications[nStart] != mpGlyphAdvances[nStart]) ) )
+ break;
+
+ // stop when the y-position of the next glyph is unexpected
+ if( mpGlyphOffsets && (mpGlyphOffsets[nStart].dv != aGOffset.dv) )
+ break;
+ }
+
+ ++nStart;
+ nStartx8 = (nStart << 8) + nSubIter;
+ return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::MoveGlyph( int nStartx8, long nNewXPos )
+{
+ DBG_ASSERT( !(nStartx8 & 0xff), "USP::MoveGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
+ if( nStart > mnGlyphCount )
+ return;
+
+ VisualItem* pVI = mpVisualItems;
+ int nMinGlyphPos = 0, nEndGlyphPos;
+ if( nStart == 0 ) // nStart==0 for first visible glyph
+ {
+ for( int i = mnItemCount; --i >= 0; ++pVI )
+ if( GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos ) )
+ break;
+ nStart = nMinGlyphPos;
+ DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::MoveG overflow" );
+ }
+ else //if( nStart > 0 ) // nStart>0 means absolute_glyphpos+1
+ {
+ --nStart;
+ for( int i = mnItemCount; --i >= 0; ++pVI )
+ if( (nStart >= pVI->mnMinGlyphPos) && (nStart < pVI->mnEndGlyphPos) )
+ break;
+ bool bRC = GetItemSubrange( *pVI, nMinGlyphPos, nEndGlyphPos );
+ (void)bRC; // avoid var-not-used warning
+ DBG_ASSERT( bRC, "USPLayout::MoveG GISR() returned false" );
+ }
+
+ long nDelta = nNewXPos - pVI->mnXOffset;
+ if( nStart > nMinGlyphPos )
+ {
+ // move the glyph by expanding its left glyph but ignore dropped glyphs
+ int i, nLastUndropped = nMinGlyphPos - 1;
+ for( i = nMinGlyphPos; i < nStart; ++i )
+ {
+ if (mpOutGlyphs[i] != DROPPED_OUTGLYPH)
+ {
+ nDelta -= (mpJustifications)? mpJustifications[ i ] : mpGlyphAdvances[ i ];
+ nLastUndropped = i;
+ }
+ }
+ if (nLastUndropped >= nMinGlyphPos)
+ {
+ mpGlyphAdvances[ nLastUndropped ] += nDelta;
+ if (mpJustifications) mpJustifications[ nLastUndropped ] += nDelta;
+ }
+ else
+ {
+ pVI->mnXOffset += nDelta;
+ }
+ }
+ else
+ {
+ // move the visual item by having an offset
+ pVI->mnXOffset += nDelta;
+ }
+ // move subsequent items - this often isn't necessary because subsequent
+ // moves will correct subsequent items. However, if there is a contiguous
+ // range not involving fallback which spans items, this will be needed
+ while (++pVI - mpVisualItems < mnItemCount)
+ {
+ pVI->mnXOffset += nDelta;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::DropGlyph( int nStartx8 )
+{
+ DBG_ASSERT( !(nStartx8 & 0xff), "USP::DropGlyph(): glyph injection not disabled!" );
+ int nStart = nStartx8 >> 8;
+ DBG_ASSERT( nStart<=mnGlyphCount, "USPLayout::MoveG nStart overflow" );
+
+ if( nStart > 0 ) // nStart>0 means absolute glyph pos + 1
+ --nStart;
+ else // nStart<=0 for first visible glyph
+ {
+ VisualItem* pVI = mpVisualItems;
+ for( int i = mnItemCount, nDummy; --i >= 0; ++pVI )
+ if( GetItemSubrange( *pVI, nStart, nDummy ) )
+ break;
+ DBG_ASSERT( nStart <= mnGlyphCount, "USPLayout::DropG overflow" );
+ int nOffset = 0;
+ int j = pVI->mnMinGlyphPos;
+ while (mpOutGlyphs[j] == DROPPED_OUTGLYPH) j++;
+ if (j == nStart)
+ {
+ pVI->mnXOffset += ((mpJustifications)? mpJustifications[nStart] : mpGlyphAdvances[nStart]);
+ }
+ }
+
+ mpOutGlyphs[ nStart ] = DROPPED_OUTGLYPH;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::Simplify( bool /*bIsBase*/ )
+{
+ static const WCHAR cDroppedGlyph = DROPPED_OUTGLYPH;
+ int i;
+ // if there are no dropped glyphs don't bother
+ for( i = 0; i < mnGlyphCount; ++i )
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ break;
+ if( i >= mnGlyphCount )
+ return;
+
+ // prepare for sparse layout
+ // => make sure mpGlyphs2Chars[] exists
+ if( !mpGlyphs2Chars )
+ {
+ mpGlyphs2Chars = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpGlyphs2Chars[ i ] = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ // skip invisible items
+ VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+ for( i = rVI.mnEndCharPos; --i >= rVI.mnMinCharPos; )
+ {
+ int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
+ mpGlyphs2Chars[ j ] = i;
+ }
+ }
+ }
+
+ // remove the dropped glyphs
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVI = mpVisualItems[ nItem ];
+ if( rVI.IsEmpty() )
+ continue;
+
+ // mark replaced character widths
+ for( i = rVI.mnMinCharPos; i < rVI.mnEndCharPos; ++i )
+ {
+ int j = mpLogClusters[ i ] + rVI.mnMinGlyphPos;
+ if( mpOutGlyphs[ j ] == cDroppedGlyph )
+ mpCharWidths[ i ] = 0;
+ }
+
+ // handle dropped glyphs at start of visual item
+ int nMinGlyphPos, nEndGlyphPos, nOrigMinGlyphPos = rVI.mnMinGlyphPos;
+ GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos );
+ i = nMinGlyphPos;
+ while( (mpOutGlyphs[i] == cDroppedGlyph) && (i < nEndGlyphPos) )
+ {
+ //rVI.mnXOffset += pGlyphWidths[ i ];
+ rVI.mnMinGlyphPos = ++i;
+ }
+
+ // when all glyphs in item got dropped mark it as empty
+ if( i >= nEndGlyphPos )
+ {
+ rVI.mnEndGlyphPos = 0;
+ continue;
+ }
+ // If there are still glyphs in the cluster and mnMinGlyphPos
+ // has changed then we need to remove the dropped glyphs at start
+ // to correct logClusters, which is unsigned and relative to the
+ // item start.
+ if (rVI.mnMinGlyphPos != nOrigMinGlyphPos)
+ {
+ // drop any glyphs in the visual item outside the range
+ for (i = nOrigMinGlyphPos; i < nMinGlyphPos; i++)
+ mpOutGlyphs[ i ] = cDroppedGlyph;
+ rVI.mnMinGlyphPos = i = nOrigMinGlyphPos;
+ }
+
+ // handle dropped glyphs in the middle of visual item
+ for(; i < nEndGlyphPos; ++i )
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ break;
+ int j = i;
+ while( ++i < nEndGlyphPos )
+ {
+ if( mpOutGlyphs[ i ] == cDroppedGlyph )
+ continue;
+ mpOutGlyphs[ j ] = mpOutGlyphs[ i ];
+ mpGlyphOffsets[ j ] = mpGlyphOffsets[ i ];
+ mpVisualAttrs[ j ] = mpVisualAttrs[ i ];
+ mpGlyphAdvances[ j ] = mpGlyphAdvances[ i ];
+ if( mpJustifications )
+ mpJustifications[ j ] = mpJustifications[ i ];
+ const int k = mpGlyphs2Chars[ i ];
+ mpGlyphs2Chars[ j ] = k;
+ const int nRelGlyphPos = (j++) - rVI.mnMinGlyphPos;
+ if( k < 0) // extra glyphs are already mapped
+ continue;
+ mpLogClusters[ k ] = static_cast<WORD>(nRelGlyphPos);
+ }
+
+ rVI.mnEndGlyphPos = j;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::DrawText( SalGraphics& ) const
+{
+ HFONT hOrigFont = DisableFontScaling();
+
+ int nBaseClusterOffset = 0;
+ int nBaseGlyphPos = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // skip if there is nothing to display
+ int nMinGlyphPos, nEndGlyphPos;
+ if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ continue;
+
+ if( nBaseGlyphPos < 0 )
+ {
+ // adjust draw position relative to cluster start
+ if( rVisualItem.IsRTL() )
+ nBaseGlyphPos = nEndGlyphPos - 1;
+ else
+ nBaseGlyphPos = nMinGlyphPos;
+
+ const int* pGlyphWidths;
+ if( mpJustifications )
+ pGlyphWidths = mpJustifications;
+ else
+ pGlyphWidths = mpGlyphAdvances;
+
+ int i = mnMinCharPos;
+ while( (--i >= rVisualItem.mnMinCharPos)
+ && (nBaseGlyphPos == mpLogClusters[i]) )
+ nBaseClusterOffset += mpCharWidths[i];
+
+ if( !rVisualItem.IsRTL() )
+ nBaseClusterOffset = -nBaseClusterOffset;
+ }
+
+ // now draw the matching glyphs in this item
+ Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
+ Point aPos = GetDrawPosition( aRelPos );
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ (*pScriptTextOut)( mhDC, &rScriptCache,
+ aPos.X(), aPos.Y(), 0, NULL,
+ &rVisualItem.mpScriptItem->a, NULL, 0,
+ mpOutGlyphs + nMinGlyphPos,
+ nEndGlyphPos - nMinGlyphPos,
+ mpGlyphAdvances + nMinGlyphPos,
+ mpJustifications ? mpJustifications + nMinGlyphPos : NULL,
+ mpGlyphOffsets + nMinGlyphPos );
+ }
+
+ if( hOrigFont )
+ DeleteFont( SelectFont( mhDC, hOrigFont ) );
+}
+
+// -----------------------------------------------------------------------
+
+long UniscribeLayout::FillDXArray( long* pDXArray ) const
+{
+ // calculate width of the complete layout
+ long nWidth = mnBaseAdv;
+ for( int nItem = mnItemCount; --nItem >= 0; )
+ {
+ const VisualItem& rVI = mpVisualItems[ nItem ];
+
+ // skip if there is nothing to display
+ int nMinGlyphPos, nEndGlyphPos;
+ if( !GetItemSubrange( rVI, nMinGlyphPos, nEndGlyphPos ) )
+ continue;
+
+ // width = xoffset + width of last item
+ nWidth = rVI.mnXOffset;
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ nWidth += pGlyphWidths[i];
+ break;
+ }
+
+ // copy the virtual char widths into pDXArray[]
+ if( pDXArray )
+ for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
+ pDXArray[ i - mnMinCharPos ] = mpCharWidths[ i ];
+
+ return nWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int UniscribeLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ long nWidth = 0;
+ for( int i = mnMinCharPos; i < mnEndCharPos; ++i )
+ {
+ nWidth += mpCharWidths[ i ] * nFactor;
+
+ // check if the nMaxWidth still fits the current sub-layout
+ if( nWidth >= nMaxWidth )
+ {
+ // go back to cluster start
+ // we have to find the visual item first since the mpLogClusters[]
+ // needed to find the cluster start is relative to to the visual item
+ int nMinGlyphIndex = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
+ if( (i >= rVisualItem.mnMinCharPos)
+ && (i < rVisualItem.mnEndCharPos) )
+ break;
+ }
+ // now go back to the matching cluster start
+ do
+ {
+ int nGlyphPos = mpLogClusters[i] + nMinGlyphIndex;
+ if( 0 != mpVisualAttrs[ nGlyphPos ].fClusterStart )
+ return i;
+ } while( --i >= mnMinCharPos );
+
+ // if the cluster starts before the start of the visual item
+ // then set the visual breakpoint before this item
+ return mnMinCharPos;
+ }
+
+ // the visual break also depends on the nCharExtra between the characters
+ nWidth += nCharExtra;
+ }
+
+ // the whole layout did fit inside the nMaxWidth
+ return STRING_LEN;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::GetCaretPositions( int nMaxIdx, long* pCaretXArray ) const
+{
+ int i;
+ for( i = 0; i < nMaxIdx; ++i )
+ pCaretXArray[ i ] = -1;
+ long* const pGlyphPos = (long*)alloca( (mnGlyphCount+1) * sizeof(long) );
+ for( i = 0; i <= mnGlyphCount; ++i )
+ pGlyphPos[ i ] = -1;
+
+ long nXPos = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( rVisualItem.IsEmpty() )
+ continue;
+
+ if (mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK)
+ {
+ nXPos = rVisualItem.mnXOffset;
+ }
+ // get glyph positions
+ // TODO: handle when rVisualItem's glyph range is only partially used
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ {
+ pGlyphPos[ i ] = nXPos;
+ nXPos += mpGlyphAdvances[ i ];
+ }
+ // rightmost position of this visualitem
+ pGlyphPos[ i ] = nXPos;
+
+ // convert glyph positions to character positions
+ i = rVisualItem.mnMinCharPos;
+ if( i < mnMinCharPos )
+ i = mnMinCharPos;
+ for(; (i < rVisualItem.mnEndCharPos) && (i < mnEndCharPos); ++i )
+ {
+ int j = mpLogClusters[ i ] + rVisualItem.mnMinGlyphPos;
+ int nCurrIdx = i * 2;
+ if( !rVisualItem.IsRTL() )
+ {
+ // normal positions for LTR case
+ pCaretXArray[ nCurrIdx ] = pGlyphPos[ j ];
+ pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j+1 ];
+ }
+ else
+ {
+ // reverse positions for RTL case
+ pCaretXArray[ nCurrIdx ] = pGlyphPos[ j+1 ];
+ pCaretXArray[ nCurrIdx+1 ] = pGlyphPos[ j ];
+ }
+ }
+ }
+
+ if (!(mnLayoutFlags & SAL_LAYOUT_FOR_FALLBACK))
+ {
+ nXPos = 0;
+ // fixup unknown character positions to neighbor
+ for( i = 0; i < nMaxIdx; ++i )
+ {
+ if( pCaretXArray[ i ] >= 0 )
+ nXPos = pCaretXArray[ i ];
+ else
+ pCaretXArray[ i ] = nXPos;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+ SalLayout::AdjustLayout( rArgs );
+
+ // adjust positions if requested
+ if( rArgs.mpDXArray )
+ ApplyDXArray( rArgs );
+ else if( rArgs.mnLayoutWidth )
+ Justify( rArgs.mnLayoutWidth );
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::ApplyDXArray( const ImplLayoutArgs& rArgs )
+{
+ const long* pDXArray = rArgs.mpDXArray;
+
+ // increase char widths in string range to desired values
+ bool bModified = false;
+ int nOldWidth = 0;
+ DBG_ASSERT( mnUnitsPerPixel==1, "UniscribeLayout.mnUnitsPerPixel != 1" );
+ int i,j;
+ for( i = mnMinCharPos, j = 0; i < mnEndCharPos; ++i, ++j )
+ {
+ int nNewCharWidth = (pDXArray[j] - nOldWidth);
+ // TODO: nNewCharWidth *= mnUnitsPerPixel;
+ if( mpCharWidths[i] != nNewCharWidth )
+ {
+ mpCharWidths[i] = nNewCharWidth;
+ bModified = true;
+ }
+ nOldWidth = pDXArray[j];
+ }
+
+ if( !bModified )
+ return;
+
+ // initialize justifications array
+ mpJustifications = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCount; ++i )
+ mpJustifications[ i ] = mpGlyphAdvances[ i ];
+
+ // apply new widths to script items
+ long nXOffset = 0;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // set the position of this visual item
+ rVisualItem.mnXOffset = nXOffset;
+
+ // ignore empty visual items
+ if( rVisualItem.IsEmpty() )
+ {
+ for (i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; i++)
+ nXOffset += mpCharWidths[i];
+ continue;
+ }
+ // ignore irrelevant visual items
+ if( (rVisualItem.mnMinCharPos >= mnEndCharPos)
+ || (rVisualItem.mnEndCharPos <= mnMinCharPos) )
+ continue;
+
+ // if needed prepare special handling for arabic justification
+ rVisualItem.mbHasKashidas = false;
+ if( rVisualItem.IsRTL() )
+ {
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ if ( (1U << mpVisualAttrs[i].uJustification) & 0xFF82 ) // any Arabic justification
+ { // excluding SCRIPT_JUSTIFY_NONE
+ // yes
+ rVisualItem.mbHasKashidas = true;
+ // so prepare for kashida handling
+ InitKashidaHandling();
+ break;
+ }
+
+ if( rVisualItem.HasKashidas() )
+ for( i = rVisualItem.mnMinGlyphPos; i < rVisualItem.mnEndGlyphPos; ++i )
+ {
+ // TODO: check if we still need this hack after correction of kashida placing?
+ // (i87688): apparently yes, we still need it!
+ if ( mpVisualAttrs[i].uJustification == SCRIPT_JUSTIFY_NONE )
+ // usp decided that justification can't be applied here
+ // but maybe our Kashida algorithm thinks differently.
+ // To avoid trouble (gaps within words, last character of
+ // a word gets a Kashida appended) override this.
+
+ // I chose SCRIPT_JUSTIFY_ARABIC_KASHIDA to replace SCRIPT_JUSTIFY_NONE
+ // just because this previous hack (which I haven't understand, sorry) used
+ // the same value to replace. Don't know if this is really the best
+ // thing to do, but it seems to fix things
+ mpVisualAttrs[i].uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
+ }
+ }
+
+ // convert virtual charwidths to glyph justification values
+ HRESULT nRC = (*pScriptApplyLogicalWidth)(
+ mpCharWidths + rVisualItem.mnMinCharPos,
+ rVisualItem.mnEndCharPos - rVisualItem.mnMinCharPos,
+ rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
+ mpLogClusters + rVisualItem.mnMinCharPos,
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ &rVisualItem.mpScriptItem->a,
+ &rVisualItem.maABCWidths,
+ mpJustifications + rVisualItem.mnMinGlyphPos );
+
+ if( nRC != 0 )
+ {
+ delete[] mpJustifications;
+ mpJustifications = NULL;
+ break;
+ }
+
+ // to prepare for the next visual item
+ // update nXOffset to the next items position
+ // before the mpJustifications[] array gets modified
+ int nMinGlyphPos, nEndGlyphPos;
+ if( GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ {
+ for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ nXOffset += mpJustifications[ i ];
+
+ if( rVisualItem.mbHasKashidas )
+ KashidaItemFix( nMinGlyphPos, nEndGlyphPos );
+ }
+
+ // workaround needed for older USP versions:
+ // right align the justification-adjusted glyphs in their cells for RTL-items
+ // unless the right alignment is done by inserting kashidas
+ if( bManualCellAlign && rVisualItem.IsRTL() && !rVisualItem.HasKashidas() )
+ {
+ for( i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ {
+ const int nXOffsetAdjust = mpJustifications[i] - mpGlyphAdvances[i];
+ // #i99862# skip diacritics, we mustn't add extra justification to diacritics
+ int nIdxAdd = i - 1;
+ while( (nIdxAdd >= nMinGlyphPos) && !mpGlyphAdvances[nIdxAdd] )
+ --nIdxAdd;
+ if( nIdxAdd < nMinGlyphPos )
+ rVisualItem.mnXOffset += nXOffsetAdjust;
+ else
+ mpJustifications[nIdxAdd] += nXOffsetAdjust;
+ mpJustifications[i] -= nXOffsetAdjust;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::InitKashidaHandling()
+{
+ if( mnMinKashidaGlyph != 0 ) // already initialized
+ return;
+
+ mrWinFontEntry.InitKashidaHandling( mhDC );
+ mnMinKashidaWidth = static_cast<int>(mfFontScale * mrWinFontEntry.GetMinKashidaWidth());
+ mnMinKashidaGlyph = mrWinFontEntry.GetMinKashidaGlyph();
+}
+
+// adjust the kashida placement matching to the WriterEngine
+void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos )
+{
+ // workaround needed for all known USP versions:
+ // ApplyLogicalWidth does not match ScriptJustify behaviour
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; ++i )
+ {
+ // check for vowels
+ if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ])
+ && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types
+ { // including SCRIPT_JUSTIFY_NONE
+ // vowel, we do it like ScriptJustify does
+ // the vowel gets the extra width
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ mpJustifications [ i ] = mpGlyphAdvances [ i ];
+ mpJustifications [ i - 1 ] += nSpaceAdded;
+ }
+ }
+
+ // redistribute the widths for kashidas
+ for( int i = nMinGlyphPos; i < nEndGlyphPos; )
+ KashidaWordFix ( nMinGlyphPos, nEndGlyphPos, &i );
+}
+
+bool UniscribeLayout::KashidaWordFix ( int nMinGlyphPos, int nEndGlyphPos, int* pnCurrentPos )
+{
+ // doing pixel work within a word.
+ // sometimes we have extra pixels and sometimes we miss some pixels to get to mnMinKashidaWidth
+
+ // find the next kashida
+ int nMinPos = *pnCurrentPos;
+ int nMaxPos = *pnCurrentPos;
+ for( int i = nMaxPos; i < nEndGlyphPos; ++i )
+ {
+ if( (mpVisualAttrs[ i ].uJustification >= SCRIPT_JUSTIFY_ARABIC_BLANK)
+ && (mpVisualAttrs[ i ].uJustification < SCRIPT_JUSTIFY_ARABIC_NORMAL) )
+ break;
+ nMaxPos = i;
+ }
+ *pnCurrentPos = nMaxPos + 1;
+ if( nMinPos == nMaxPos )
+ return false;
+
+ // calculate the available space for an extra kashida
+ long nMaxAdded = 0;
+ int nKashPos = -1;
+ for( int i = nMaxPos; i >= nMinPos; --i )
+ {
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > nMaxAdded )
+ {
+ nKashPos = i;
+ nMaxAdded = nSpaceAdded;
+ }
+ }
+
+ // return early if there is no need for an extra kashida
+ if ( nMaxAdded <= 0 )
+ return false;
+ // return early if there is not enough space for an extra kashida
+ if( 2*nMaxAdded < mnMinKashidaWidth )
+ return false;
+
+ // redistribute the extra spacing to the kashida position
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ // everything else should not have extra spacing
+ long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ];
+ if( nSpaceAdded > 0 )
+ {
+ mpJustifications[ i ] -= nSpaceAdded;
+ mpJustifications[ nKashPos ] += nSpaceAdded;
+ }
+ }
+
+ // check if we fulfill minimal kashida width
+ long nSpaceAdded = mpJustifications[ nKashPos ] - mpGlyphAdvances[ nKashPos ];
+ if( nSpaceAdded < mnMinKashidaWidth )
+ {
+ // ugly: steal some pixels
+ long nSteal = 1;
+ if ( nMaxPos - nMinPos > 0 && ((mnMinKashidaWidth - nSpaceAdded) > (nMaxPos - nMinPos)))
+ nSteal = (mnMinKashidaWidth - nSpaceAdded) / (nMaxPos - nMinPos);
+ for( int i = nMinPos; i <= nMaxPos; ++i )
+ {
+ if( i == nKashPos )
+ continue;
+ nSteal = Min( mnMinKashidaWidth - nSpaceAdded, nSteal );
+ if ( nSteal > 0 )
+ {
+ mpJustifications [ i ] -= nSteal;
+ mpJustifications [ nKashPos ] += nSteal;
+ nSpaceAdded += nSteal;
+ }
+ if( nSpaceAdded >= mnMinKashidaWidth )
+ return true;
+ }
+ }
+
+ // blank padding
+ long nSpaceMissing = mnMinKashidaWidth - nSpaceAdded;
+ if( nSpaceMissing > 0 )
+ {
+ // inner glyph: distribute extra space evenly
+ if( (nMinPos > nMinGlyphPos) && (nMaxPos < nEndGlyphPos - 1) )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ long nHalfSpace = nSpaceMissing / 2;
+ mpJustifications [ nMinPos - 1 ] -= nHalfSpace;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing - nHalfSpace;
+ }
+ // rightmost: left glyph gets extra space
+ else if( nMinPos > nMinGlyphPos )
+ {
+ mpJustifications [ nMinPos - 1 ] -= nSpaceMissing;
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ }
+ // leftmost: right glyph gets extra space
+ else if( nMaxPos < nEndGlyphPos - 1 )
+ {
+ mpJustifications [ nKashPos ] += nSpaceMissing;
+ mpJustifications [ nMaxPos + 1 ] -= nSpaceMissing;
+ }
+ else
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void UniscribeLayout::Justify( long nNewWidth )
+{
+ long nOldWidth = 0;
+ int i;
+ for( i = mnMinCharPos; i < mnEndCharPos; ++i )
+ nOldWidth += mpCharWidths[ i ];
+ if( nOldWidth <= 0 )
+ return;
+
+ nNewWidth *= mnUnitsPerPixel; // convert into font units
+ if( nNewWidth == nOldWidth )
+ return;
+ // prepare to distribute the extra width evenly among the visual items
+ const double fStretch = (double)nNewWidth / nOldWidth;
+
+ // initialize justifications array
+ mpJustifications = new int[ mnGlyphCapacity ];
+ for( i = 0; i < mnGlyphCapacity; ++i )
+ mpJustifications[ i ] = mpGlyphAdvances[ i ];
+
+ // justify stretched script items
+ long nXOffset = 0;
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( rVisualItem.IsEmpty() )
+ continue;
+
+ if( (rVisualItem.mnMinCharPos < mnEndCharPos)
+ && (rVisualItem.mnEndCharPos > mnMinCharPos) )
+ {
+ long nItemWidth = 0;
+ for( i = rVisualItem.mnMinCharPos; i < rVisualItem.mnEndCharPos; ++i )
+ nItemWidth += mpCharWidths[ i ];
+ nItemWidth = (int)((fStretch - 1.0) * nItemWidth + 0.5);
+
+ HRESULT nRC = (*pScriptJustify) (
+ mpVisualAttrs + rVisualItem.mnMinGlyphPos,
+ mpGlyphAdvances + rVisualItem.mnMinGlyphPos,
+ rVisualItem.mnEndGlyphPos - rVisualItem.mnMinGlyphPos,
+ nItemWidth,
+ mnMinKashidaWidth,
+ mpJustifications + rVisualItem.mnMinGlyphPos );
+
+ rVisualItem.mnXOffset = nXOffset;
+ nXOffset += nItemWidth;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const
+{
+ // we have to find the visual item first since the mpLogClusters[]
+ // needed to find the cluster start is relative to to the visual item
+ int nMinGlyphIndex = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+ if( (nCharPos >= rVisualItem.mnMinCharPos)
+ && (nCharPos < rVisualItem.mnEndCharPos) )
+ {
+ nMinGlyphIndex = rVisualItem.mnMinGlyphPos;
+ break;
+ }
+ }
+ // Invalid char pos or leftmost glyph in visual item
+ if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] )
+ return false;
+
+// This test didn't give the expected results
+/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ])
+ // two chars, one glyph
+ return false;*/
+
+ const int nGlyphPos = mpLogClusters[ nCharPos ] + nMinGlyphIndex;
+ if( nGlyphPos <= 0 )
+ return true;
+ // justification is only allowed if the glyph to the left has not SCRIPT_JUSTIFY_NONE
+ // and not SCRIPT_JUSTIFY_ARABIC_BLANK
+ // special case: glyph to the left is vowel (no advance width)
+ if ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_ARABIC_BLANK
+ || ( mpVisualAttrs[ nGlyphPos-1 ].uJustification == SCRIPT_JUSTIFY_NONE
+ && mpGlyphAdvances [ nGlyphPos-1 ] ))
+ return false;
+ return true;
+}
+
+#endif // USE_UNISCRIBE
+
+#ifdef ENABLE_GRAPHITE
+
+class GraphiteLayoutWinImpl : public GraphiteLayout
+{
+public:
+ GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont)
+ throw()
+ : GraphiteLayout(font), mrFont(rFont) {};
+ virtual ~GraphiteLayoutWinImpl() throw() {};
+ virtual sal_GlyphId getKashidaGlyph(int & rWidth);
+private:
+ ImplWinFontEntry & mrFont;
+};
+
+sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth)
+{
+ rWidth = mrFont.GetMinKashidaWidth();
+ return mrFont.GetMinKashidaGlyph();
+}
+
+// This class uses the SIL Graphite engine to provide complex text layout services to the VCL
+// @author tse
+//
+class GraphiteWinLayout : public WinLayout
+{
+private:
+ mutable GraphiteWinFont mpFont;
+ grutils::GrFeatureParser * mpFeatures;
+ mutable GraphiteLayoutWinImpl maImpl;
+public:
+ GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE);
+
+ static bool IsGraphiteEnabledFont(HDC hDC) throw();
+
+ // used by upper layers
+ virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout
+ virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc.
+ // virtual void InitFont() const;
+ virtual void DrawText( SalGraphics& ) const;
+
+ // methods using string indexing
+ virtual int GetTextBreak( long nMaxWidth, long nCharExtra=0, int nFactor=1 ) const;
+ virtual long FillDXArray( long* pDXArray ) const;
+
+ virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const;
+
+ // methods using glyph indexing
+ virtual int GetNextGlyphs(int nLen, sal_GlyphId* pGlyphIdxAry, ::Point & rPos, int&,
+ long* pGlyphAdvAry = 0, int* pCharPosAry = 0 ) const;
+
+ // used by glyph+font+script fallback
+ virtual void MoveGlyph( int nStart, long nNewXPos );
+ virtual void DropGlyph( int nStart );
+ virtual void Simplify( bool bIsBase );
+ ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; };
+protected:
+ virtual void ReplaceDC(gr::Segment & segment) const;
+ virtual void RestoreDC(gr::Segment & segment) const;
+};
+
+bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw()
+{
+ return gr::WinFont::FontHasGraphiteTables(hDC);
+}
+
+GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw()
+ : WinLayout(hDC, rWFD, rWFE), mpFont(hDC),
+ maImpl(mpFont, rWFE)
+{
+ const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage );
+ rtl::OString name = rtl::OUStringToOString(
+ rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
+ sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
+ if (nFeat > 0)
+ {
+ rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
+ mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr());
+ }
+ else
+ {
+ mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr());
+ }
+ maImpl.SetFeatures(mpFeatures);
+}
+
+void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const
+{
+ COLORREF color = GetTextColor(mhDC);
+ dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC);
+ SetTextColor(mhDC, color);
+}
+
+void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const
+{
+ dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC();
+}
+
+bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args)
+{
+ if (args.mnMinCharPos >= args.mnEndCharPos)
+ {
+ maImpl.clear();
+ return true;
+ }
+ HFONT hUnRotatedFont;
+ if (args.mnOrientation)
+ {
+ // Graphite gets very confused if the font is rotated
+ LOGFONTW aLogFont;
+ ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont);
+ aLogFont.lfEscapement = 0;
+ aLogFont.lfOrientation = 0;
+ hUnRotatedFont = ::CreateFontIndirectW( &aLogFont);
+ ::SelectFont(mhDC, hUnRotatedFont);
+ }
+ WinLayout::AdjustLayout(args);
+ mpFont.replaceDC(mhDC);
+ maImpl.SetFontScale(WinLayout::mfFontScale);
+ //bool succeeded = maImpl.LayoutText(args);
+#ifdef GRCACHE
+ GrSegRecord * pSegRecord = NULL;
+ gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord);
+#else
+ gr::Segment * pSegment = maImpl.CreateSegment(args);
+#endif
+ bool bSucceeded = false;
+ if (pSegment)
+ {
+ // replace the DC on the font within the segment
+ ReplaceDC(*pSegment);
+ // create glyph vectors
+#ifdef GRCACHE
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord);
+#else
+ bSucceeded = maImpl.LayoutGlyphs(args, pSegment);
+#endif
+ // restore original DC
+ RestoreDC(*pSegment);
+#ifdef GRCACHE
+ if (pSegRecord) pSegRecord->unlock();
+ else delete pSegment;
+#else
+ delete pSegment;
+#endif
+ }
+ mpFont.restoreDC();
+ if (args.mnOrientation)
+ {
+ // restore the rotated font
+ ::SelectFont(mhDC, mhFont);
+ ::DeleteObject(hUnRotatedFont);
+ }
+ return bSucceeded;
+}
+
+void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
+{
+ WinLayout::AdjustLayout(rArgs);
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ if ( (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL) && rArgs.mpDXArray)
+ {
+ mrWinFontEntry.InitKashidaHandling(mhDC);
+ }
+ maImpl.AdjustLayout(rArgs);
+}
+
+void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const
+{
+ HFONT hOrigFont = DisableFontScaling();
+ HDC aHDC = static_cast<WinSalGraphics&>(sal_graphics).mhDC;
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ const int MAX_GLYPHS = 2;
+ sal_GlyphId glyphIntStr[MAX_GLYPHS];
+ WORD glyphWStr[MAX_GLYPHS];
+ int glyphIndex = 0;
+ Point aPos(0,0);
+ int nGlyphs = 0;
+ do
+ {
+ nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex);
+ if (nGlyphs < 1)
+ break;
+ std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
+ ::ExtTextOutW(aHDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX,
+ NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
+ } while (nGlyphs);
+ if( hOrigFont )
+ DeleteFont( SelectFont( mhDC, hOrigFont ) );
+}
+
+int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+ mpFont.replaceDC(mhDC);
+ int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor);
+ mpFont.restoreDC();
+ return nBreak;
+}
+
+long GraphiteWinLayout::FillDXArray( long* pDXArray ) const
+{
+ return maImpl.FillDXArray(pDXArray);
+}
+
+void GraphiteWinLayout::GetCaretPositions( int nArraySize, long* pCaretXArray ) const
+{
+ maImpl.GetCaretPositions(nArraySize, pCaretXArray);
+}
+
+int GraphiteWinLayout::GetNextGlyphs( int length, sal_GlyphId* glyph_out,
+ ::Point & pos_out, int &glyph_slot, long * glyph_adv, int *char_index) const
+{
+ maImpl.DrawBase() = WinLayout::maDrawBase;
+ maImpl.DrawOffset() = WinLayout::maDrawOffset;
+ return maImpl.GetNextGlyphs(length, glyph_out, pos_out, glyph_slot, glyph_adv, char_index);
+}
+
+void GraphiteWinLayout::MoveGlyph( int glyph_idx, long new_x_pos )
+{
+ maImpl.MoveGlyph(glyph_idx, new_x_pos);
+}
+
+void GraphiteWinLayout::DropGlyph( int glyph_idx )
+{
+ maImpl.DropGlyph(glyph_idx);
+}
+
+void GraphiteWinLayout::Simplify( bool is_base )
+{
+ maImpl.Simplify(is_base);
+}
+#endif // ENABLE_GRAPHITE
+// =======================================================================
+
+SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
+{
+ DBG_ASSERT( mpWinFontEntry[nFallbackLevel], "WinSalGraphics mpWinFontEntry==NULL");
+
+ WinLayout* pWinLayout = NULL;
+
+ const ImplWinFontData& rFontFace = *mpWinFontData[ nFallbackLevel ];
+ ImplWinFontEntry& rFontInstance = *mpWinFontEntry[ nFallbackLevel ];
+
+#if defined( USE_UNISCRIBE )
+ if( !(rArgs.mnFlags & SAL_LAYOUT_COMPLEX_DISABLED)
+ && (aUspModule || (bUspEnabled && InitUSP())) ) // CTL layout engine
+ {
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
+ // script complexity is determined in upper layers
+ pWinLayout = new UniscribeLayout( mhDC, rFontFace, rFontInstance );
+ // NOTE: it must be guaranteed that the WinSalGraphics lives longer than
+ // the created UniscribeLayout, otherwise the data passed into the
+ // constructor might become invalid too early
+ }
+ else
+#endif // USE_UNISCRIBE
+ {
+#ifdef GCP_KERN_HACK
+ if( (rArgs.mnFlags & SAL_LAYOUT_KERNING_PAIRS) && !rFontInstance.HasKernData() )
+ {
+ // TODO: directly cache kerning info in the rFontInstance
+ // TODO: get rid of kerning methods+data in WinSalGraphics object
+ GetKernPairs( 0, NULL );
+ rFontInstance.SetKernData( mnFontKernPairCount, mpFontKernPairs );
+ }
+#endif // GCP_KERN_HACK
+
+ BYTE eCharSet = ANSI_CHARSET;
+ if( mpLogFont )
+ eCharSet = mpLogFont->lfCharSet;
+#ifdef ENABLE_GRAPHITE
+ if (rFontFace.SupportsGraphite())
+ pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance);
+ else
+#endif // ENABLE_GRAPHITE
+ pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance );
+ }
+
+ if( mfFontScale != 1.0 )
+ pWinLayout->SetFontScale( mfFontScale );
+
+ return pWinLayout;
+}
+
+// -----------------------------------------------------------------------
+
+int WinSalGraphics::GetMinKashidaWidth()
+{
+ if( !mpWinFontEntry[0] )
+ return 0;
+ mpWinFontEntry[0]->InitKashidaHandling( mhDC );
+ int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth());
+ return nMinKashida;
+}
+
+// =======================================================================
+
+ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD )
+: ImplFontEntry( rFSD )
+, maWidthMap( 512 )
+, mpKerningPairs( NULL )
+, mnKerningPairs( -1 )
+, mnMinKashidaWidth( -1 )
+, mnMinKashidaGlyph( -1 )
+{
+#ifdef USE_UNISCRIBE
+ maScriptCache = NULL;
+#endif // USE_UNISCRIBE
+}
+
+// -----------------------------------------------------------------------
+
+ImplWinFontEntry::~ImplWinFontEntry()
+{
+#ifdef USE_UNISCRIBE
+ if( maScriptCache != NULL )
+ (*pScriptFreeCache)( &maScriptCache );
+#endif // USE_UNISCRIBE
+#ifdef GCP_KERN_HACK
+ delete[] mpKerningPairs;
+#endif // GCP_KERN_HACK
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontEntry::HasKernData() const
+{
+ return (mnKerningPairs >= 0);
+}
+
+// -----------------------------------------------------------------------
+
+void ImplWinFontEntry::SetKernData( int nPairCount, const KERNINGPAIR* pPairData )
+{
+ mnKerningPairs = nPairCount;
+ mpKerningPairs = new KERNINGPAIR[ mnKerningPairs ];
+ ::memcpy( mpKerningPairs, (const void*)pPairData, nPairCount*sizeof(KERNINGPAIR) );
+}
+
+// -----------------------------------------------------------------------
+
+int ImplWinFontEntry::GetKerning( sal_Unicode cLeft, sal_Unicode cRight ) const
+{
+ int nKernAmount = 0;
+ if( mpKerningPairs )
+ {
+ const KERNINGPAIR aRefPair = { cLeft, cRight, 0 };
+ const KERNINGPAIR* pFirstPair = mpKerningPairs;
+ const KERNINGPAIR* pEndPair = mpKerningPairs + mnKerningPairs;
+ const KERNINGPAIR* pPair = std::lower_bound( pFirstPair,
+ pEndPair, aRefPair, ImplCmpKernData );
+ if( (pPair != pEndPair)
+ && (pPair->wFirst == aRefPair.wFirst)
+ && (pPair->wSecond == aRefPair.wSecond) )
+ nKernAmount = pPair->iKernAmount;
+ }
+
+ return nKernAmount;
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplWinFontEntry::InitKashidaHandling( HDC hDC )
+{
+ if( mnMinKashidaWidth >= 0 ) // already cached?
+ return mnMinKashidaWidth;
+
+ // initialize the kashida width
+ mnMinKashidaWidth = 0;
+ mnMinKashidaGlyph = 0;
+#ifdef USE_UNISCRIBE
+ if (aUspModule || (bUspEnabled && InitUSP()))
+ {
+ SCRIPT_FONTPROPERTIES aFontProperties;
+ aFontProperties.cBytes = sizeof (aFontProperties);
+ SCRIPT_CACHE& rScriptCache = GetScriptCache();
+ HRESULT nRC = (*pScriptGetFontProperties)( hDC, &rScriptCache, &aFontProperties );
+ if( nRC != 0 )
+ return false;
+ mnMinKashidaWidth = aFontProperties.iKashidaWidth;
+ mnMinKashidaGlyph = aFontProperties.wgKashida;
+ }
+#endif // USE_UNISCRIBE
+
+ return true;
+}
+
+// =======================================================================
+
+ImplFontData* ImplWinFontData::Clone() const
+{
+ if( mpUnicodeMap )
+ mpUnicodeMap->AddReference();
+ ImplFontData* pClone = new ImplWinFontData( *this );
+ return pClone;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplWinFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
+{
+ ImplFontEntry* pEntry = new ImplWinFontEntry( rFSD );
+ return pEntry;
+}
+
+// =======================================================================
diff --git a/vcl/win/source/gdi/wntgdi.cxx b/vcl/win/source/gdi/wntgdi.cxx
new file mode 100755
index 000000000000..eb53fb4d8699
--- /dev/null
+++ b/vcl/win/source/gdi/wntgdi.cxx
@@ -0,0 +1,67 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#if defined _MSC_VER
+#pragma warning(push, 1)
+#endif
+#include <windows.h>
+#if defined _MSC_VER
+#pragma warning(pop)
+#endif
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_Rectangle( HDC hDC, int X1, int Y1, int X2, int Y2 )
+{
+ return Rectangle( hDC, X1, Y1, X2, Y2 );
+}
+}
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_Polygon( HDC hDC, CONST POINT * ppt, int ncnt )
+{
+ return Polygon( hDC, ppt, ncnt );
+}
+}
+
+// -----------------------------------------------------------------------
+
+extern "C"
+{
+BOOL WINAPI WIN_PolyPolygon( HDC hDC, CONST POINT * ppt, LPINT npcnt, int ncnt )
+{
+ return PolyPolygon( hDC, ppt, npcnt, ncnt );
+}
+}
diff --git a/vcl/win/source/src/50.bmp b/vcl/win/source/src/50.bmp
new file mode 100644
index 000000000000..b9d56fcd14c1
--- /dev/null
+++ b/vcl/win/source/src/50.bmp
Binary files differ
diff --git a/vcl/win/source/src/50.png b/vcl/win/source/src/50.png
new file mode 100644
index 000000000000..8517d965f0b9
--- /dev/null
+++ b/vcl/win/source/src/50.png
Binary files differ
diff --git a/vcl/win/source/src/airbrush.cur b/vcl/win/source/src/airbrush.cur
new file mode 100644
index 000000000000..f6a684e6fcbd
--- /dev/null
+++ b/vcl/win/source/src/airbrush.cur
Binary files differ
diff --git a/vcl/win/source/src/ase.cur b/vcl/win/source/src/ase.cur
new file mode 100755
index 000000000000..7634a7d34a7b
--- /dev/null
+++ b/vcl/win/source/src/ase.cur
Binary files differ
diff --git a/vcl/win/source/src/asn.cur b/vcl/win/source/src/asn.cur
new file mode 100755
index 000000000000..e444e42bf37e
--- /dev/null
+++ b/vcl/win/source/src/asn.cur
Binary files differ
diff --git a/vcl/win/source/src/asne.cur b/vcl/win/source/src/asne.cur
new file mode 100755
index 000000000000..e92cc65e7eb1
--- /dev/null
+++ b/vcl/win/source/src/asne.cur
Binary files differ
diff --git a/vcl/win/source/src/asns.cur b/vcl/win/source/src/asns.cur
new file mode 100755
index 000000000000..04d0b09c353e
--- /dev/null
+++ b/vcl/win/source/src/asns.cur
Binary files differ
diff --git a/vcl/win/source/src/asnswe.cur b/vcl/win/source/src/asnswe.cur
new file mode 100755
index 000000000000..a0e25b16de1f
--- /dev/null
+++ b/vcl/win/source/src/asnswe.cur
Binary files differ
diff --git a/vcl/win/source/src/asnw.cur b/vcl/win/source/src/asnw.cur
new file mode 100755
index 000000000000..20322bc97b16
--- /dev/null
+++ b/vcl/win/source/src/asnw.cur
Binary files differ
diff --git a/vcl/win/source/src/ass.cur b/vcl/win/source/src/ass.cur
new file mode 100755
index 000000000000..7166636a1a77
--- /dev/null
+++ b/vcl/win/source/src/ass.cur
Binary files differ
diff --git a/vcl/win/source/src/asse.cur b/vcl/win/source/src/asse.cur
new file mode 100755
index 000000000000..8cb71234b0a9
--- /dev/null
+++ b/vcl/win/source/src/asse.cur
Binary files differ
diff --git a/vcl/win/source/src/assw.cur b/vcl/win/source/src/assw.cur
new file mode 100755
index 000000000000..fddaf3f57cbf
--- /dev/null
+++ b/vcl/win/source/src/assw.cur
Binary files differ
diff --git a/vcl/win/source/src/asw.cur b/vcl/win/source/src/asw.cur
new file mode 100755
index 000000000000..0ccac50f4596
--- /dev/null
+++ b/vcl/win/source/src/asw.cur
Binary files differ
diff --git a/vcl/win/source/src/aswe.cur b/vcl/win/source/src/aswe.cur
new file mode 100755
index 000000000000..c238b7e10aef
--- /dev/null
+++ b/vcl/win/source/src/aswe.cur
Binary files differ
diff --git a/vcl/win/source/src/chain.cur b/vcl/win/source/src/chain.cur
new file mode 100755
index 000000000000..02abb7ab714f
--- /dev/null
+++ b/vcl/win/source/src/chain.cur
Binary files differ
diff --git a/vcl/win/source/src/chainnot.cur b/vcl/win/source/src/chainnot.cur
new file mode 100755
index 000000000000..938ece03f329
--- /dev/null
+++ b/vcl/win/source/src/chainnot.cur
Binary files differ
diff --git a/vcl/win/source/src/chart.cur b/vcl/win/source/src/chart.cur
new file mode 100644
index 000000000000..25fe85b76039
--- /dev/null
+++ b/vcl/win/source/src/chart.cur
Binary files differ
diff --git a/vcl/win/source/src/copydata.cur b/vcl/win/source/src/copydata.cur
new file mode 100644
index 000000000000..d3c4bc93afd5
--- /dev/null
+++ b/vcl/win/source/src/copydata.cur
Binary files differ
diff --git a/vcl/win/source/src/copydlnk.cur b/vcl/win/source/src/copydlnk.cur
new file mode 100644
index 000000000000..495fd5e17776
--- /dev/null
+++ b/vcl/win/source/src/copydlnk.cur
Binary files differ
diff --git a/vcl/win/source/src/copyf.cur b/vcl/win/source/src/copyf.cur
new file mode 100644
index 000000000000..450c09443a84
--- /dev/null
+++ b/vcl/win/source/src/copyf.cur
Binary files differ
diff --git a/vcl/win/source/src/copyf2.cur b/vcl/win/source/src/copyf2.cur
new file mode 100644
index 000000000000..ac8de5da6ba5
--- /dev/null
+++ b/vcl/win/source/src/copyf2.cur
Binary files differ
diff --git a/vcl/win/source/src/copyflnk.cur b/vcl/win/source/src/copyflnk.cur
new file mode 100644
index 000000000000..e67f0539fa43
--- /dev/null
+++ b/vcl/win/source/src/copyflnk.cur
Binary files differ
diff --git a/vcl/win/source/src/crook.cur b/vcl/win/source/src/crook.cur
new file mode 100644
index 000000000000..c40cf591e261
--- /dev/null
+++ b/vcl/win/source/src/crook.cur
Binary files differ
diff --git a/vcl/win/source/src/crop.cur b/vcl/win/source/src/crop.cur
new file mode 100644
index 000000000000..327fb06976c2
--- /dev/null
+++ b/vcl/win/source/src/crop.cur
Binary files differ
diff --git a/vcl/win/source/src/cross.cur b/vcl/win/source/src/cross.cur
new file mode 100644
index 000000000000..8fd9762386b1
--- /dev/null
+++ b/vcl/win/source/src/cross.cur
Binary files differ
diff --git a/vcl/win/source/src/darc.cur b/vcl/win/source/src/darc.cur
new file mode 100644
index 000000000000..38504fa23c4a
--- /dev/null
+++ b/vcl/win/source/src/darc.cur
Binary files differ
diff --git a/vcl/win/source/src/dbezier.cur b/vcl/win/source/src/dbezier.cur
new file mode 100644
index 000000000000..f630b837ddf8
--- /dev/null
+++ b/vcl/win/source/src/dbezier.cur
Binary files differ
diff --git a/vcl/win/source/src/dcapt.cur b/vcl/win/source/src/dcapt.cur
new file mode 100644
index 000000000000..10dd5ba0d676
--- /dev/null
+++ b/vcl/win/source/src/dcapt.cur
Binary files differ
diff --git a/vcl/win/source/src/dcirccut.cur b/vcl/win/source/src/dcirccut.cur
new file mode 100644
index 000000000000..b19d3f8257f4
--- /dev/null
+++ b/vcl/win/source/src/dcirccut.cur
Binary files differ
diff --git a/vcl/win/source/src/dconnect.cur b/vcl/win/source/src/dconnect.cur
new file mode 100644
index 000000000000..5318d8f22d8b
--- /dev/null
+++ b/vcl/win/source/src/dconnect.cur
Binary files differ
diff --git a/vcl/win/source/src/dellipse.cur b/vcl/win/source/src/dellipse.cur
new file mode 100644
index 000000000000..c489a640335e
--- /dev/null
+++ b/vcl/win/source/src/dellipse.cur
Binary files differ
diff --git a/vcl/win/source/src/detectiv.cur b/vcl/win/source/src/detectiv.cur
new file mode 100644
index 000000000000..30e5685b64b2
--- /dev/null
+++ b/vcl/win/source/src/detectiv.cur
Binary files differ
diff --git a/vcl/win/source/src/dfree.cur b/vcl/win/source/src/dfree.cur
new file mode 100644
index 000000000000..3ff56d007648
--- /dev/null
+++ b/vcl/win/source/src/dfree.cur
Binary files differ
diff --git a/vcl/win/source/src/dline.cur b/vcl/win/source/src/dline.cur
new file mode 100644
index 000000000000..623c33ac2351
--- /dev/null
+++ b/vcl/win/source/src/dline.cur
Binary files differ
diff --git a/vcl/win/source/src/dpie.cur b/vcl/win/source/src/dpie.cur
new file mode 100644
index 000000000000..3b911cd01e43
--- /dev/null
+++ b/vcl/win/source/src/dpie.cur
Binary files differ
diff --git a/vcl/win/source/src/dpolygon.cur b/vcl/win/source/src/dpolygon.cur
new file mode 100644
index 000000000000..9467f1e286aa
--- /dev/null
+++ b/vcl/win/source/src/dpolygon.cur
Binary files differ
diff --git a/vcl/win/source/src/drect.cur b/vcl/win/source/src/drect.cur
new file mode 100644
index 000000000000..60a5242c203c
--- /dev/null
+++ b/vcl/win/source/src/drect.cur
Binary files differ
diff --git a/vcl/win/source/src/dtext.cur b/vcl/win/source/src/dtext.cur
new file mode 100644
index 000000000000..01e7d31eae7e
--- /dev/null
+++ b/vcl/win/source/src/dtext.cur
Binary files differ
diff --git a/vcl/win/source/src/fill.cur b/vcl/win/source/src/fill.cur
new file mode 100644
index 000000000000..78f5fad87ad0
--- /dev/null
+++ b/vcl/win/source/src/fill.cur
Binary files differ
diff --git a/vcl/win/source/src/hand.cur b/vcl/win/source/src/hand.cur
new file mode 100644
index 000000000000..fc0e53b474e2
--- /dev/null
+++ b/vcl/win/source/src/hand.cur
Binary files differ
diff --git a/vcl/win/source/src/help.cur b/vcl/win/source/src/help.cur
new file mode 100644
index 000000000000..e59ee97992b3
--- /dev/null
+++ b/vcl/win/source/src/help.cur
Binary files differ
diff --git a/vcl/win/source/src/hshear.cur b/vcl/win/source/src/hshear.cur
new file mode 100644
index 000000000000..5cf2211458c3
--- /dev/null
+++ b/vcl/win/source/src/hshear.cur
Binary files differ
diff --git a/vcl/win/source/src/hsize.cur b/vcl/win/source/src/hsize.cur
new file mode 100644
index 000000000000..571dd0ef703c
--- /dev/null
+++ b/vcl/win/source/src/hsize.cur
Binary files differ
diff --git a/vcl/win/source/src/hsizebar.cur b/vcl/win/source/src/hsizebar.cur
new file mode 100644
index 000000000000..dda3483bb5d4
--- /dev/null
+++ b/vcl/win/source/src/hsizebar.cur
Binary files differ
diff --git a/vcl/win/source/src/hsplit.cur b/vcl/win/source/src/hsplit.cur
new file mode 100644
index 000000000000..f2f0be363d3a
--- /dev/null
+++ b/vcl/win/source/src/hsplit.cur
Binary files differ
diff --git a/vcl/win/source/src/linkdata.cur b/vcl/win/source/src/linkdata.cur
new file mode 100644
index 000000000000..e47c1dea2cec
--- /dev/null
+++ b/vcl/win/source/src/linkdata.cur
Binary files differ
diff --git a/vcl/win/source/src/linkf.cur b/vcl/win/source/src/linkf.cur
new file mode 100644
index 000000000000..6cc498a02610
--- /dev/null
+++ b/vcl/win/source/src/linkf.cur
Binary files differ
diff --git a/vcl/win/source/src/magnify.cur b/vcl/win/source/src/magnify.cur
new file mode 100644
index 000000000000..1e32b92351af
--- /dev/null
+++ b/vcl/win/source/src/magnify.cur
Binary files differ
diff --git a/vcl/win/source/src/mirror.cur b/vcl/win/source/src/mirror.cur
new file mode 100644
index 000000000000..e05eb836eb5d
--- /dev/null
+++ b/vcl/win/source/src/mirror.cur
Binary files differ
diff --git a/vcl/win/source/src/move.cur b/vcl/win/source/src/move.cur
new file mode 100644
index 000000000000..a407a1298ad5
--- /dev/null
+++ b/vcl/win/source/src/move.cur
Binary files differ
diff --git a/vcl/win/source/src/movebw.cur b/vcl/win/source/src/movebw.cur
new file mode 100644
index 000000000000..d079eb9fe20d
--- /dev/null
+++ b/vcl/win/source/src/movebw.cur
Binary files differ
diff --git a/vcl/win/source/src/movedata.cur b/vcl/win/source/src/movedata.cur
new file mode 100644
index 000000000000..4d67cbe47149
--- /dev/null
+++ b/vcl/win/source/src/movedata.cur
Binary files differ
diff --git a/vcl/win/source/src/movedlnk.cur b/vcl/win/source/src/movedlnk.cur
new file mode 100644
index 000000000000..1bb7b0306406
--- /dev/null
+++ b/vcl/win/source/src/movedlnk.cur
Binary files differ
diff --git a/vcl/win/source/src/movef.cur b/vcl/win/source/src/movef.cur
new file mode 100644
index 000000000000..6abee2381dcf
--- /dev/null
+++ b/vcl/win/source/src/movef.cur
Binary files differ
diff --git a/vcl/win/source/src/movef2.cur b/vcl/win/source/src/movef2.cur
new file mode 100644
index 000000000000..d044981a3ffd
--- /dev/null
+++ b/vcl/win/source/src/movef2.cur
Binary files differ
diff --git a/vcl/win/source/src/moveflnk.cur b/vcl/win/source/src/moveflnk.cur
new file mode 100644
index 000000000000..630fa1bc3e4e
--- /dev/null
+++ b/vcl/win/source/src/moveflnk.cur
Binary files differ
diff --git a/vcl/win/source/src/movept.cur b/vcl/win/source/src/movept.cur
new file mode 100644
index 000000000000..81d3af5a05c4
--- /dev/null
+++ b/vcl/win/source/src/movept.cur
Binary files differ
diff --git a/vcl/win/source/src/neswsize.cur b/vcl/win/source/src/neswsize.cur
new file mode 100644
index 000000000000..c38501ee15a8
--- /dev/null
+++ b/vcl/win/source/src/neswsize.cur
Binary files differ
diff --git a/vcl/win/source/src/notallow.cur b/vcl/win/source/src/notallow.cur
new file mode 100644
index 000000000000..90c1dfbb3a97
--- /dev/null
+++ b/vcl/win/source/src/notallow.cur
Binary files differ
diff --git a/vcl/win/source/src/nullptr.cur b/vcl/win/source/src/nullptr.cur
new file mode 100644
index 000000000000..28dbb2a903f2
--- /dev/null
+++ b/vcl/win/source/src/nullptr.cur
Binary files differ
diff --git a/vcl/win/source/src/nwsesize.cur b/vcl/win/source/src/nwsesize.cur
new file mode 100644
index 000000000000..570cbbb571cc
--- /dev/null
+++ b/vcl/win/source/src/nwsesize.cur
Binary files differ
diff --git a/vcl/win/source/src/pen.cur b/vcl/win/source/src/pen.cur
new file mode 100644
index 000000000000..040c5dc703e9
--- /dev/null
+++ b/vcl/win/source/src/pen.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotcol.cur b/vcl/win/source/src/pivotcol.cur
new file mode 100644
index 000000000000..061b3ba92644
--- /dev/null
+++ b/vcl/win/source/src/pivotcol.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotdel.cur b/vcl/win/source/src/pivotdel.cur
new file mode 100644
index 000000000000..4497dacd9983
--- /dev/null
+++ b/vcl/win/source/src/pivotdel.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotfld.cur b/vcl/win/source/src/pivotfld.cur
new file mode 100644
index 000000000000..efbbead8930c
--- /dev/null
+++ b/vcl/win/source/src/pivotfld.cur
Binary files differ
diff --git a/vcl/win/source/src/pivotrow.cur b/vcl/win/source/src/pivotrow.cur
new file mode 100644
index 000000000000..649444e9e132
--- /dev/null
+++ b/vcl/win/source/src/pivotrow.cur
Binary files differ
diff --git a/vcl/win/source/src/pntbrsh.cur b/vcl/win/source/src/pntbrsh.cur
new file mode 100644
index 000000000000..517d114237c1
--- /dev/null
+++ b/vcl/win/source/src/pntbrsh.cur
Binary files differ
diff --git a/vcl/win/source/src/refhand.cur b/vcl/win/source/src/refhand.cur
new file mode 100644
index 000000000000..a654974c6f8b
--- /dev/null
+++ b/vcl/win/source/src/refhand.cur
Binary files differ
diff --git a/vcl/win/source/src/rotate.cur b/vcl/win/source/src/rotate.cur
new file mode 100644
index 000000000000..43c2a54a10ac
--- /dev/null
+++ b/vcl/win/source/src/rotate.cur
Binary files differ
diff --git a/vcl/win/source/src/salsrc.rc b/vcl/win/source/src/salsrc.rc
new file mode 100755
index 000000000000..11b967ff475b
--- /dev/null
+++ b/vcl/win/source/src/salsrc.rc
@@ -0,0 +1,121 @@
+/*************************************************************************
+*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+**************************************************************************/
+
+// for WINVER
+#include <windows.h>
+
+#ifndef _SV_SALIDS_HRC
+#include <win/salids.hrc>
+#endif
+
+SAL_RESID_POINTER_NULL CURSOR NULLPTR.CUR
+#if ( WINVER < 0x0400 )
+SAL_RESID_POINTER_HELP CURSOR HELP.CUR
+#endif
+#ifndef WNT
+SAL_RESID_POINTER_HSIZE CURSOR HSIZE.CUR
+SAL_RESID_POINTER_VSIZE CURSOR VSIZE.CUR
+SAL_RESID_POINTER_NESWSIZE CURSOR NESWSIZE.CUR
+SAL_RESID_POINTER_NWSESIZE CURSOR NWSESIZE.CUR
+#endif
+SAL_RESID_POINTER_CROSS CURSOR CROSS.CUR
+SAL_RESID_POINTER_MOVE CURSOR MOVE.CUR
+SAL_RESID_POINTER_HSPLIT CURSOR HSPLIT.CUR
+SAL_RESID_POINTER_VSPLIT CURSOR VSPLIT.CUR
+SAL_RESID_POINTER_HSIZEBAR CURSOR HSIZEBAR.CUR
+SAL_RESID_POINTER_VSIZEBAR CURSOR VSIZEBAR.CUR
+SAL_RESID_POINTER_HAND CURSOR HAND.CUR
+SAL_RESID_POINTER_REFHAND CURSOR REFHAND.CUR
+SAL_RESID_POINTER_PEN CURSOR PEN.CUR
+SAL_RESID_POINTER_MAGNIFY CURSOR MAGNIFY.CUR
+SAL_RESID_POINTER_FILL CURSOR FILL.CUR
+SAL_RESID_POINTER_ROTATE CURSOR ROTATE.CUR
+SAL_RESID_POINTER_HSHEAR CURSOR HSHEAR.CUR
+SAL_RESID_POINTER_VSHEAR CURSOR VSHEAR.CUR
+SAL_RESID_POINTER_MIRROR CURSOR MIRROR.CUR
+SAL_RESID_POINTER_CROOK CURSOR CROOK.CUR
+SAL_RESID_POINTER_CROP CURSOR CROP.CUR
+SAL_RESID_POINTER_MOVEPOINT CURSOR MOVEPT.CUR
+SAL_RESID_POINTER_MOVEBEZIERWEIGHT CURSOR MOVEBW.CUR
+SAL_RESID_POINTER_MOVEDATA CURSOR MOVEDATA.CUR
+SAL_RESID_POINTER_COPYDATA CURSOR COPYDATA.CUR
+SAL_RESID_POINTER_LINKDATA CURSOR LINKDATA.CUR
+SAL_RESID_POINTER_MOVEDATALINK CURSOR MOVEDLNK.CUR
+SAL_RESID_POINTER_COPYDATALINK CURSOR COPYDLNK.CUR
+SAL_RESID_POINTER_MOVEFILE CURSOR MOVEF.CUR
+SAL_RESID_POINTER_COPYFILE CURSOR COPYF.CUR
+SAL_RESID_POINTER_LINKFILE CURSOR LINKF.CUR
+SAL_RESID_POINTER_MOVEFILELINK CURSOR MOVEFLNK.CUR
+SAL_RESID_POINTER_COPYFILELINK CURSOR COPYFLNK.CUR
+SAL_RESID_POINTER_MOVEFILES CURSOR MOVEF2.CUR
+SAL_RESID_POINTER_COPYFILES CURSOR COPYF2.CUR
+SAL_RESID_POINTER_NOTALLOWED CURSOR NOTALLOW.CUR
+SAL_RESID_POINTER_DRAW_LINE CURSOR DLINE.CUR
+SAL_RESID_POINTER_DRAW_RECT CURSOR DRECT.CUR
+SAL_RESID_POINTER_DRAW_POLYGON CURSOR DPOLYGON.CUR
+SAL_RESID_POINTER_DRAW_BEZIER CURSOR DBEZIER.CUR
+SAL_RESID_POINTER_DRAW_ARC CURSOR DARC.CUR
+SAL_RESID_POINTER_DRAW_PIE CURSOR DPIE.CUR
+SAL_RESID_POINTER_DRAW_CIRCLECUT CURSOR DCIRCCUT.CUR
+SAL_RESID_POINTER_DRAW_ELLIPSE CURSOR DELLIPSE.CUR
+SAL_RESID_POINTER_DRAW_FREEHAND CURSOR DFREE.CUR
+SAL_RESID_POINTER_DRAW_CONNECT CURSOR DCONNECT.CUR
+SAL_RESID_POINTER_DRAW_TEXT CURSOR DTEXT.CUR
+SAL_RESID_POINTER_DRAW_CAPTION CURSOR DCAPT.CUR
+SAL_RESID_POINTER_CHART CURSOR CHART.CUR
+SAL_RESID_POINTER_DETECTIVE CURSOR DETECTIV.CUR
+SAL_RESID_POINTER_PIVOT_COL CURSOR PIVOTCOL.CUR
+SAL_RESID_POINTER_PIVOT_ROW CURSOR PIVOTROW.CUR
+SAL_RESID_POINTER_PIVOT_FIELD CURSOR PIVOTFLD.CUR
+SAL_RESID_POINTER_PIVOT_DELETE CURSOR PIVOTDEL.CUR
+SAL_RESID_POINTER_CHAIN CURSOR CHAIN.CUR
+SAL_RESID_POINTER_CHAIN_NOTALLOWED CURSOR CHAINNOT.CUR
+SAL_RESID_POINTER_TIMEEVENT_MOVE CURSOR TIMEMOVE.CUR
+SAL_RESID_POINTER_TIMEEVENT_SIZE CURSOR TIMESIZE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_N CURSOR ASN.CUR
+SAL_RESID_POINTER_AUTOSCROLL_S CURSOR ASS.CUR
+SAL_RESID_POINTER_AUTOSCROLL_W CURSOR ASW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_E CURSOR ASE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NW CURSOR ASNW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NE CURSOR ASNE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_SW CURSOR ASSW.CUR
+SAL_RESID_POINTER_AUTOSCROLL_SE CURSOR ASSE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NS CURSOR ASNS.CUR
+SAL_RESID_POINTER_AUTOSCROLL_WE CURSOR ASWE.CUR
+SAL_RESID_POINTER_AUTOSCROLL_NSWE CURSOR ASNSWE.CUR
+SAL_RESID_POINTER_AIRBRUSH CURSOR AIRBRUSH.CUR
+SAL_RESID_POINTER_TEXT_VERTICAL CURSOR VTEXT.CUR
+SAL_RESID_POINTER_TAB_SELECT_S CURSOR TBLSELS.CUR
+SAL_RESID_POINTER_TAB_SELECT_E CURSOR TBLSELE.CUR
+SAL_RESID_POINTER_TAB_SELECT_SE CURSOR TBLSELSE.CUR
+SAL_RESID_POINTER_TAB_SELECT_W CURSOR TBLSELW.CUR
+SAL_RESID_POINTER_TAB_SELECT_SW CURSOR TBLSELSW.CUR
+SAL_RESID_POINTER_PAINTBRUSH CURSOR PNTBRSH.CUR
+
+SAL_RESID_BITMAP_50 BITMAP 50.BMP
+
+SAL_RESID_ICON_DEFAULT ICON SD.ICO
diff --git a/vcl/win/source/src/sd.ico b/vcl/win/source/src/sd.ico
new file mode 100644
index 000000000000..b2a0a07a67c3
--- /dev/null
+++ b/vcl/win/source/src/sd.ico
Binary files differ
diff --git a/vcl/win/source/src/tblsele.cur b/vcl/win/source/src/tblsele.cur
new file mode 100644
index 000000000000..3683e20df112
--- /dev/null
+++ b/vcl/win/source/src/tblsele.cur
Binary files differ
diff --git a/vcl/win/source/src/tblsels.cur b/vcl/win/source/src/tblsels.cur
new file mode 100644
index 000000000000..007182d734de
--- /dev/null
+++ b/vcl/win/source/src/tblsels.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselse.cur b/vcl/win/source/src/tblselse.cur
new file mode 100644
index 000000000000..986f0139501a
--- /dev/null
+++ b/vcl/win/source/src/tblselse.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselsw.cur b/vcl/win/source/src/tblselsw.cur
new file mode 100644
index 000000000000..adabba1a2adc
--- /dev/null
+++ b/vcl/win/source/src/tblselsw.cur
Binary files differ
diff --git a/vcl/win/source/src/tblselw.cur b/vcl/win/source/src/tblselw.cur
new file mode 100644
index 000000000000..a95eb85af49a
--- /dev/null
+++ b/vcl/win/source/src/tblselw.cur
Binary files differ
diff --git a/vcl/win/source/src/timemove.cur b/vcl/win/source/src/timemove.cur
new file mode 100755
index 000000000000..319b6edc5774
--- /dev/null
+++ b/vcl/win/source/src/timemove.cur
Binary files differ
diff --git a/vcl/win/source/src/timesize.cur b/vcl/win/source/src/timesize.cur
new file mode 100755
index 000000000000..1ec23de05b71
--- /dev/null
+++ b/vcl/win/source/src/timesize.cur
Binary files differ
diff --git a/vcl/win/source/src/vshear.cur b/vcl/win/source/src/vshear.cur
new file mode 100644
index 000000000000..a4bbf7e8eb00
--- /dev/null
+++ b/vcl/win/source/src/vshear.cur
Binary files differ
diff --git a/vcl/win/source/src/vsize.cur b/vcl/win/source/src/vsize.cur
new file mode 100644
index 000000000000..76449be89d0a
--- /dev/null
+++ b/vcl/win/source/src/vsize.cur
Binary files differ
diff --git a/vcl/win/source/src/vsizebar.cur b/vcl/win/source/src/vsizebar.cur
new file mode 100644
index 000000000000..a87811cb474d
--- /dev/null
+++ b/vcl/win/source/src/vsizebar.cur
Binary files differ
diff --git a/vcl/win/source/src/vsplit.cur b/vcl/win/source/src/vsplit.cur
new file mode 100644
index 000000000000..a4260808fadc
--- /dev/null
+++ b/vcl/win/source/src/vsplit.cur
Binary files differ
diff --git a/vcl/win/source/src/vtext.cur b/vcl/win/source/src/vtext.cur
new file mode 100644
index 000000000000..776177901e11
--- /dev/null
+++ b/vcl/win/source/src/vtext.cur
Binary files differ
diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx
new file mode 100755
index 000000000000..bcbaee6d8b6c
--- /dev/null
+++ b/vcl/win/source/window/salframe.cxx
@@ -0,0 +1,6388 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+// i72022: ad-hoc to forcibly enable reconversion
+#if WINVER < 0x0500
+#undef WINVER
+#define WINVER 0x0500
+#endif
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/misccfg.hxx>
+
+#include <string.h>
+#include <limits.h>
+
+#include <stdio.h>
+
+#include <tools/svwin.h>
+#ifdef __MINGW32__
+#include <excpt.h>
+#endif
+
+#include <rtl/string.h>
+#include <rtl/ustring.h>
+
+#include <osl/module.h>
+
+#include <tools/debug.hxx>
+
+#include <vcl/sysdata.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/keycodes.hxx>
+#include <vcl/window.hxx>
+#include <vcl/wrkwin.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/impdel.hxx>
+
+// Warning in SDK header
+#if defined(_MSC_VER) && (_MSC_VER > 1400)
+#pragma warning( disable: 4242 4244 )
+#endif
+#include <win/wincomp.hxx>
+#include <win/salids.hrc>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salbmp.h>
+#include <win/salgdi.h>
+#include <win/salsys.h>
+#include <win/salframe.h>
+#include <win/salvd.h>
+#include <win/salmenu.h>
+#include <win/salobj.h>
+#include <win/saltimer.h>
+
+#include <impbmp.hxx>
+#include <window.h>
+#include <sallayout.hxx>
+
+#define COMPILE_MULTIMON_STUBS
+#include <multimon.h>
+#include <vector>
+#ifdef __MINGW32__
+#include <algorithm>
+using ::std::max;
+#endif
+
+#include <com/sun/star/uno/Exception.hdl>
+
+#include <time.h>
+
+using ::rtl::OUString;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::beans;
+
+// The following defines are newly added in Longhorn
+#ifndef WM_MOUSEHWHEEL
+# define WM_MOUSEHWHEEL 0x020E
+#endif
+#ifndef SPI_GETWHEELSCROLLCHARS
+# define SPI_GETWHEELSCROLLCHARS 0x006C
+#endif
+#ifndef SPI_SETWHEELSCROLLCHARS
+# define SPI_SETWHEELSCROLLCHARS 0x006D
+#endif
+
+
+
+#if OSL_DEBUG_LEVEL > 1
+void MyOutputDebugString( char *s) { OutputDebugString( s ); }
+#endif
+
+// misssing prototypes and constants for LayeredWindows
+extern "C" {
+ //WINUSERAPI sal_Bool WINAPI SetLayeredWindowAttributes(HWND,COLORREF,BYTE,DWORD);
+ typedef sal_Bool ( WINAPI * SetLayeredWindowAttributes_Proc_T ) (HWND,COLORREF,BYTE,DWORD);
+ static SetLayeredWindowAttributes_Proc_T lpfnSetLayeredWindowAttributes;
+};
+
+// =======================================================================
+
+const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageA("SYSTEM_WINDOW_ACTIVATED");
+
+sal_Bool WinSalFrame::mbInReparent = FALSE;
+
+// =======================================================================
+
+// Wegen Fehler in Windows-Headerfiles
+#ifndef IMN_OPENCANDIDATE
+#define IMN_OPENCANDIDATE 0x0005
+#endif
+#ifndef IMN_CLOSECANDIDATE
+#define IMN_CLOSECANDIDATE 0x0004
+#endif
+
+#ifndef WM_THEMECHANGED
+#define WM_THEMECHANGED 0x031A
+#endif
+
+// Macros for support of WM_UNICHAR & Keyman 6.0
+#define Uni_UTF32ToSurrogate1(ch) (((unsigned long) (ch) - 0x10000) / 0x400 + 0xD800)
+#define Uni_UTF32ToSurrogate2(ch) (((unsigned long) (ch) - 0x10000) % 0x400 + 0xDC00)
+#define Uni_SupplementaryPlanesStart 0x10000
+
+// =======================================================================
+
+static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame );
+static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect = NULL );
+
+static void ImplSaveFrameState( WinSalFrame* pFrame )
+{
+ // Position, Groesse und Status fuer GetWindowState() merken
+ if ( !pFrame->mbFullScreen )
+ {
+ sal_Bool bVisible = (GetWindowStyle( pFrame->mhWnd ) & WS_VISIBLE) != 0;
+ if ( IsIconic( pFrame->mhWnd ) )
+ {
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MINIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ else if ( IsZoomed( pFrame->mhWnd ) )
+ {
+ pFrame->maState.mnState &= ~SAL_FRAMESTATE_MINIMIZED;
+ pFrame->maState.mnState |= SAL_FRAMESTATE_MAXIMIZED;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ pFrame->mbRestoreMaximize = TRUE;
+
+ WINDOWPLACEMENT aPlacement;
+ aPlacement.length = sizeof(aPlacement);
+ if( GetWindowPlacement( pFrame->mhWnd, &aPlacement ) )
+ {
+ RECT aRect = aPlacement.rcNormalPosition;
+ RECT aRect2 = aRect;
+ AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ),
+ FALSE, GetWindowExStyle( pFrame->mhWnd ) );
+ long nTopDeco = abs( aRect.top - aRect2.top );
+ long nLeftDeco = abs( aRect.left - aRect2.left );
+ long nBottomDeco = abs( aRect.bottom - aRect2.bottom );
+ long nRightDeco = abs( aRect.right - aRect2.right );
+
+ pFrame->maState.mnX = aRect.left + nLeftDeco;
+ pFrame->maState.mnY = aRect.top + nTopDeco;
+ pFrame->maState.mnWidth = aRect.right - aRect.left - nLeftDeco - nRightDeco;
+ pFrame->maState.mnHeight = aRect.bottom - aRect.top - nTopDeco - nBottomDeco;
+ }
+ }
+ else
+ {
+ RECT aRect;
+ GetWindowRect( pFrame->mhWnd, &aRect );
+
+ // to be consistent with Unix, the frame state is without(!) decoration
+ RECT aRect2 = aRect;
+ AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ),
+ FALSE, GetWindowExStyle( pFrame->mhWnd ) );
+ long nTopDeco = abs( aRect.top - aRect2.top );
+ long nLeftDeco = abs( aRect.left - aRect2.left );
+ long nBottomDeco = abs( aRect.bottom - aRect2.bottom );
+ long nRightDeco = abs( aRect.right - aRect2.right );
+
+ pFrame->maState.mnState &= ~(SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED);
+ // subtract decoration
+ pFrame->maState.mnX = aRect.left+nLeftDeco;
+ pFrame->maState.mnY = aRect.top+nTopDeco;
+ pFrame->maState.mnWidth = aRect.right-aRect.left-nLeftDeco-nRightDeco;
+ pFrame->maState.mnHeight = aRect.bottom-aRect.top-nTopDeco-nBottomDeco;
+ if ( bVisible )
+ pFrame->mnShowState = SW_SHOWNORMAL;
+ pFrame->mbRestoreMaximize = FALSE;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+// if pParentRect is set, the workarea of the monitor that contains pParentRect is returned
+void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
+{
+ static int winVerChecked = 0;
+ static int winVerOk = 0;
+
+ // check if we or our parent is fullscreen, then the taskbar should be ignored
+ bool bIgnoreTaskbar = false;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if( pFrame )
+ {
+ Window *pWin = pFrame->GetWindow();
+ while( pWin )
+ {
+ WorkWindow *pWorkWin = (pWin->GetType() == WINDOW_WORKWINDOW) ? (WorkWindow *) pWin : NULL;
+ if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() )
+ {
+ bIgnoreTaskbar = true;
+ break;
+ }
+ else
+ pWin = pWin->ImplGetWindowImpl()->mpParent;
+ }
+ }
+
+ if( !winVerChecked )
+ {
+ winVerChecked = 1;
+ winVerOk = 1;
+
+ // multi monitor calls not available on Win95/NT
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion <= 4 )
+ winVerOk = 0; // NT
+ }
+ else if( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
+ {
+ if ( aSalShlData.maVersionInfo.dwMajorVersion == 4 && aSalShlData.maVersionInfo.dwMinorVersion == 0 )
+ winVerOk = 0; // Win95
+ }
+ }
+
+ // calculates the work area taking multiple monitors into account
+ if( winVerOk )
+ {
+ static int nMonitors = GetSystemMetrics( SM_CMONITORS );
+ if( nMonitors == 1 )
+ {
+ if( bIgnoreTaskbar )
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = GetSystemMetrics( SM_CXSCREEN );
+ pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
+ }
+ else
+ SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 );
+ }
+ else
+ {
+ if( pParentRect != NULL )
+ {
+ // return the size of the monitor where pParentRect lives
+ HMONITOR hMonitor;
+ MONITORINFO mi;
+
+ // get the nearest monitor to the passed rect.
+ hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST);
+
+ // get the work area or entire monitor rect.
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(hMonitor, &mi);
+ if( !bIgnoreTaskbar )
+ *pRect = mi.rcWork;
+ else
+ *pRect = mi.rcMonitor;
+ }
+ else
+ {
+ // return the union of all monitors
+ pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
+ pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
+ pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
+ pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
+
+ // virtualscreen does not take taskbar into account, so use the corresponding
+ // diffs between screen and workarea from the default screen
+ // however, this is still not perfect: the taskbar might not be on the primary screen
+ if( !bIgnoreTaskbar )
+ {
+ RECT wRect, scrRect;
+ SystemParametersInfo( SPI_GETWORKAREA, 0, &wRect, 0 );
+ scrRect.left = 0;
+ scrRect.top = 0;
+ scrRect.right = GetSystemMetrics( SM_CXSCREEN );
+ scrRect.bottom = GetSystemMetrics( SM_CYSCREEN );
+
+ pRect->left += wRect.left;
+ pRect->top += wRect.top;
+ pRect->right -= scrRect.right - wRect.right;
+ pRect->bottom -= scrRect.bottom - wRect.bottom;
+ }
+ }
+ }
+ }
+ else
+ {
+ if( bIgnoreTaskbar )
+ {
+ pRect->left = pRect->top = 0;
+ pRect->right = GetSystemMetrics( SM_CXSCREEN );
+ pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
+ }
+ else
+ SystemParametersInfo( SPI_GETWORKAREA, 0, pRect, 0 );
+ }
+}
+
+// =======================================================================
+
+SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
+ HWND hWndParent, sal_uLong nSalFrameStyle )
+{
+ WinSalFrame* pFrame = new WinSalFrame;
+ HWND hWnd;
+ DWORD nSysStyle = 0;
+ DWORD nExSysStyle = 0;
+ sal_Bool bSubFrame = FALSE;
+
+ if( getenv( "SAL_SYNCHRONIZE" ) ) // no buffering of drawing commands
+ GdiSetBatchLimit( 1 );
+
+ static int bLayeredAPI = -1;
+ if( bLayeredAPI == -1 )
+ {
+ bLayeredAPI = 0;
+ // check for W2k and XP
+ if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
+ {
+ OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "user32" ) );
+ oslModule pLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ oslGenericFunction pFunc = NULL;
+ if( pLib )
+ pFunc = osl_getAsciiFunctionSymbol( pLib, "SetLayeredWindowAttributes" );
+
+ lpfnSetLayeredWindowAttributes = ( SetLayeredWindowAttributes_Proc_T ) pFunc;
+
+ bLayeredAPI = pFunc ? 1 : 0;
+ }
+ }
+ static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" );
+
+ // determine creation data
+ if ( nSalFrameStyle & (SAL_FRAME_STYLE_PLUG | SAL_FRAME_STYLE_SYSTEMCHILD) )
+ {
+ nSysStyle |= WS_CHILD;
+ if( nSalFrameStyle & SAL_FRAME_STYLE_SYSTEMCHILD )
+ nSysStyle |= WS_CLIPSIBLINGS;
+ }
+ else
+ {
+ // #i87402# commenting out WS_CLIPCHILDREN
+ // this breaks SAL_FRAME_STYLE_SYSTEMCHILD handling, which is not
+ // used currently. Probably SAL_FRAME_STYLE_SYSTEMCHILD should be
+ // removed again.
+
+ // nSysStyle |= WS_CLIPCHILDREN;
+ if ( hWndParent )
+ {
+ nSysStyle |= WS_POPUP;
+ bSubFrame = TRUE;
+ pFrame->mbNoIcon = TRUE;
+ }
+ else
+ {
+ // Only with WS_OVRLAPPED we get a useful default position/size
+ if ( (nSalFrameStyle & (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE)) ==
+ (SAL_FRAME_STYLE_SIZEABLE | SAL_FRAME_STYLE_MOVEABLE) )
+ nSysStyle |= WS_OVERLAPPED;
+ else
+ {
+ nSysStyle |= WS_POPUP;
+ if ( !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) )
+ nExSysStyle |= WS_EX_TOOLWINDOW; // avoid taskbar appearance, for eg splash screen
+ }
+ }
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ {
+ pFrame->mbCaption = TRUE;
+ nSysStyle |= WS_SYSMENU | WS_CAPTION;
+ if ( !hWndParent )
+ nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX;
+ else
+ nExSysStyle |= WS_EX_DLGMODALFRAME;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE )
+ {
+ pFrame->mbSizeBorder = TRUE;
+ nSysStyle |= WS_THICKFRAME;
+ if ( !hWndParent )
+ nSysStyle |= WS_MAXIMIZEBOX;
+ }
+ else
+ pFrame->mbFixBorder = TRUE;
+
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT )
+ nExSysStyle |= WS_EX_APPWINDOW;
+ }
+ if( nSalFrameStyle & SAL_FRAME_STYLE_TOOLWINDOW
+ // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus
+ // you must press it twice to leave the application
+ // so toolwindows are only used for non sizeable windows
+ // which are typically small, so a small caption makes sense
+
+ // #103578# looked too bad - above changes reverted
+ /* && !(nSalFrameStyle & SAL_FRAME_STYLE_SIZEABLE) */ )
+ {
+ pFrame->mbNoIcon = TRUE;
+ nExSysStyle |= WS_EX_TOOLWINDOW;
+ if ( pEnvTransparentFloats && bLayeredAPI == 1 /*&& !(nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE) */)
+ nExSysStyle |= WS_EX_LAYERED;
+ }
+ }
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_FLOAT )
+ {
+ nExSysStyle |= WS_EX_TOOLWINDOW;
+ pFrame->mbFloatWin = TRUE;
+
+ if ( (bLayeredAPI == 1) && (pEnvTransparentFloats /* does not work remote! || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) */ ) )
+ nExSysStyle |= WS_EX_LAYERED;
+
+ }
+ if( (nSalFrameStyle & SAL_FRAME_STYLE_TOOLTIP) || (nSalFrameStyle & SAL_FRAME_STYLE_FLOAT_FOCUSABLE) )
+ nExSysStyle |= WS_EX_TOPMOST;
+
+ // init frame data
+ pFrame->mnStyle = nSalFrameStyle;
+
+ // determine show style
+ pFrame->mnShowState = SW_SHOWNORMAL;
+ if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) )
+ {
+ if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ else
+ {
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_DEFAULT )
+ {
+ SalData* pSalData = GetSalData();
+ pFrame->mnShowState = pSalData->mnCmdShow;
+ if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) &&
+ (pFrame->mnShowState != SW_MINIMIZE) &&
+ (pFrame->mnShowState != SW_SHOWMINNOACTIVE) )
+ {
+ if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) ||
+ (pFrame->mnShowState == SW_MAXIMIZE) )
+ pFrame->mbOverwriteState = FALSE;
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ else
+ pFrame->mbOverwriteState = FALSE;
+ }
+ else
+ {
+ // Document Windows are also maximized, if the current Document Window
+ // is also maximized
+ HWND hWnd = GetForegroundWindow();
+ if ( hWnd && IsMaximized( hWnd ) &&
+ (GetWindowInstance( hWnd ) == pInst->mhInst) &&
+ ((GetWindowStyle( hWnd ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) )
+ pFrame->mnShowState = SW_SHOWMAXIMIZED;
+ }
+ }
+ }
+
+ // create frame
+ if( true/*aSalShlData.mbWNT*/ )
+ {
+ LPCWSTR pClassName;
+ if ( bSubFrame )
+ {
+ if ( nSalFrameStyle & (SAL_FRAME_STYLE_MOVEABLE|SAL_FRAME_STYLE_NOSHADOW) ) // check if shadow not wanted
+ pClassName = SAL_SUBFRAME_CLASSNAMEW;
+ else
+ pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; // undecorated floaters will get shadow on XP
+ }
+ else
+ {
+ if ( nSalFrameStyle & SAL_FRAME_STYLE_MOVEABLE )
+ pClassName = SAL_FRAME_CLASSNAMEW;
+ else
+ pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
+ }
+ hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, pInst->mhInst, (void*)pFrame );
+ if( !hWnd )
+ ImplWriteLastError( GetLastError(), "CreateWindowEx" );
+#if OSL_DEBUG_LEVEL > 1
+ // set transparency value
+ if( bLayeredAPI == 1 && GetWindowExStyle( hWnd ) & WS_EX_LAYERED )
+ lpfnSetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ );
+#endif
+ }
+ if ( !hWnd )
+ {
+ delete pFrame;
+ return NULL;
+ }
+
+ // If we have an Window with an Caption Bar and without
+ // an MaximizeBox, we change the SystemMenu
+ if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) )
+ {
+ HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
+ if ( hSysMenu )
+ {
+ if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) )
+ DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND );
+ else
+ EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
+ if ( !(nSysStyle & WS_MINIMIZEBOX) )
+ DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND );
+ if ( !(nSysStyle & WS_MAXIMIZEBOX) )
+ DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
+ if ( !(nSysStyle & WS_THICKFRAME) )
+ DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND );
+ }
+ }
+ if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SAL_FRAME_STYLE_CLOSEABLE) )
+ {
+ HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
+ if ( hSysMenu )
+ EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
+ }
+
+ // reset input context
+ pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, 0 );
+
+ // determine output size and state
+ RECT aRect;
+ GetClientRect( hWnd, &aRect );
+ pFrame->mnWidth = aRect.right;
+ pFrame->mnHeight = aRect.bottom;
+ ImplSaveFrameState( pFrame );
+ pFrame->mbDefPos = TRUE;
+
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ if( pFrame->mnShowState == SW_SHOWMAXIMIZED )
+ {
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+
+ SetMaximizedFrameGeometry( hWnd, pFrame );
+ }
+
+ return pFrame;
+}
+
+// helper that only creates the HWND
+// to allow for easy reparenting of system windows, (i.e. destroy and create new)
+HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, sal_Bool bAsChild )
+{
+ HINSTANCE hInstance = GetSalData()->mhInst;
+ ULONG nSysStyle = GetWindowLong( oldhWnd, GWL_STYLE );
+ ULONG nExSysStyle = GetWindowLong( oldhWnd, GWL_EXSTYLE );
+
+ if( bAsChild )
+ {
+ nSysStyle = WS_CHILD;
+ nExSysStyle = 0;
+ }
+
+ LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW;
+ HWND hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) );
+ return hWnd;
+}
+
+// =======================================================================
+
+// Uebersetzungstabelle von System-Keycodes in StarView-Keycodes
+#define KEY_TAB_SIZE 146
+
+static sal_uInt16 aImplTranslateKeyTab[KEY_TAB_SIZE] =
+{
+ // StarView-Code System-Code Index
+ 0, // 0
+ 0, // VK_LBUTTON 1
+ 0, // VK_RBUTTON 2
+ 0, // VK_CANCEL 3
+ 0, // VK_MBUTTON 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ KEY_BACKSPACE, // VK_BACK 8
+ KEY_TAB, // VK_TAB 9
+ 0, // 10
+ 0, // 11
+ 0, // VK_CLEAR 12
+ KEY_RETURN, // VK_RETURN 13
+ 0, // 14
+ 0, // 15
+ 0, // VK_SHIFT 16
+ 0, // VK_CONTROL 17
+ 0, // VK_MENU 18
+ 0, // VK_PAUSE 19
+ 0, // VK_CAPITAL 20
+ 0, // VK_HANGUL 21
+ 0, // 22
+ 0, // 23
+ 0, // 24
+ KEY_HANGUL_HANJA, // VK_HANJA 25
+ 0, // 26
+ KEY_ESCAPE, // VK_ESCAPE 27
+ 0, // 28
+ 0, // 29
+ 0, // 30
+ 0, // 31
+ KEY_SPACE, // VK_SPACE 32
+ KEY_PAGEUP, // VK_PRIOR 33
+ KEY_PAGEDOWN, // VK_NEXT 34
+ KEY_END, // VK_END 35
+ KEY_HOME, // VK_HOME 36
+ KEY_LEFT, // VK_LEFT 37
+ KEY_UP, // VK_UP 38
+ KEY_RIGHT, // VK_RIGHT 39
+ KEY_DOWN, // VK_DOWN 40
+ 0, // VK_SELECT 41
+ 0, // VK_PRINT 42
+ 0, // VK_EXECUTE 43
+ 0, // VK_SNAPSHOT 44
+ KEY_INSERT, // VK_INSERT 45
+ KEY_DELETE, // VK_DELETE 46
+ KEY_HELP, // VK_HELP 47
+ KEY_0, // 48
+ KEY_1, // 49
+ KEY_2, // 50
+ KEY_3, // 51
+ KEY_4, // 52
+ KEY_5, // 53
+ KEY_6, // 54
+ KEY_7, // 55
+ KEY_8, // 56
+ KEY_9, // 57
+ 0, // 58
+ 0, // 59
+ 0, // 60
+ 0, // 61
+ 0, // 62
+ 0, // 63
+ 0, // 64
+ KEY_A, // 65
+ KEY_B, // 66
+ KEY_C, // 67
+ KEY_D, // 68
+ KEY_E, // 69
+ KEY_F, // 70
+ KEY_G, // 71
+ KEY_H, // 72
+ KEY_I, // 73
+ KEY_J, // 74
+ KEY_K, // 75
+ KEY_L, // 76
+ KEY_M, // 77
+ KEY_N, // 78
+ KEY_O, // 79
+ KEY_P, // 80
+ KEY_Q, // 81
+ KEY_R, // 82
+ KEY_S, // 83
+ KEY_T, // 84
+ KEY_U, // 85
+ KEY_V, // 86
+ KEY_W, // 87
+ KEY_X, // 88
+ KEY_Y, // 89
+ KEY_Z, // 90
+ 0, // VK_LWIN 91
+ 0, // VK_RWIN 92
+ KEY_CONTEXTMENU, // VK_APPS 93
+ 0, // 94
+ 0, // 95
+ KEY_0, // VK_NUMPAD0 96
+ KEY_1, // VK_NUMPAD1 97
+ KEY_2, // VK_NUMPAD2 98
+ KEY_3, // VK_NUMPAD3 99
+ KEY_4, // VK_NUMPAD4 100
+ KEY_5, // VK_NUMPAD5 101
+ KEY_6, // VK_NUMPAD6 102
+ KEY_7, // VK_NUMPAD7 103
+ KEY_8, // VK_NUMPAD8 104
+ KEY_9, // VK_NUMPAD9 105
+ KEY_MULTIPLY, // VK_MULTIPLY 106
+ KEY_ADD, // VK_ADD 107
+ KEY_DECIMAL, // VK_SEPARATOR 108
+ KEY_SUBTRACT, // VK_SUBTRACT 109
+ KEY_DECIMAL, // VK_DECIMAL 110
+ KEY_DIVIDE, // VK_DIVIDE 111
+ KEY_F1, // VK_F1 112
+ KEY_F2, // VK_F2 113
+ KEY_F3, // VK_F3 114
+ KEY_F4, // VK_F4 115
+ KEY_F5, // VK_F5 116
+ KEY_F6, // VK_F6 117
+ KEY_F7, // VK_F7 118
+ KEY_F8, // VK_F8 119
+ KEY_F9, // VK_F9 120
+ KEY_F10, // VK_F10 121
+ KEY_F11, // VK_F11 122
+ KEY_F12, // VK_F12 123
+ KEY_F13, // VK_F13 124
+ KEY_F14, // VK_F14 125
+ KEY_F15, // VK_F15 126
+ KEY_F16, // VK_F16 127
+ KEY_F17, // VK_F17 128
+ KEY_F18, // VK_F18 129
+ KEY_F19, // VK_F19 130
+ KEY_F20, // VK_F20 131
+ KEY_F21, // VK_F21 132
+ KEY_F22, // VK_F22 133
+ KEY_F23, // VK_F23 134
+ KEY_F24, // VK_F24 135
+ 0, // 136
+ 0, // 137
+ 0, // 138
+ 0, // 139
+ 0, // 140
+ 0, // 141
+ 0, // 142
+ 0, // 143
+ 0, // NUMLOCK 144
+ 0 // SCROLLLOCK 145
+};
+
+// =======================================================================
+
+static UINT ImplSalGetWheelScrollLines()
+{
+ UINT nScrLines = 0;
+ HWND hWndMsWheel = WIN_FindWindow( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE );
+ if ( hWndMsWheel )
+ {
+ UINT nGetScrollLinesMsgId = RegisterWindowMessage( MSH_SCROLL_LINES );
+ nScrLines = (UINT)ImplSendMessage( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 );
+ }
+
+ if ( !nScrLines )
+ if( !SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) )
+ nScrLines = 0 ;
+
+ if ( !nScrLines )
+ nScrLines = 3;
+
+ return nScrLines;
+}
+
+// -----------------------------------------------------------------------
+
+static UINT ImplSalGetWheelScrollChars()
+{
+ UINT nScrChars = 0;
+ if( !SystemParametersInfo( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) )
+ {
+ // Depending on Windows version, use proper default or 1 (when
+ // driver emulates hscroll)
+ if( VER_PLATFORM_WIN32_NT == aSalShlData.maVersionInfo.dwPlatformId &&
+ aSalShlData.maVersionInfo.dwMajorVersion < 6 )
+ {
+ // Windows 2000 & WinXP : emulating driver, use step size
+ // of 1
+ return 1;
+ }
+ else
+ {
+ // Longhorn or above: use proper default value of 3
+ return 3;
+ }
+ }
+
+ // system settings successfully read
+ return nScrChars;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height )
+{
+ // transform client size into window size
+ RECT aWinRect;
+ aWinRect.left = 0;
+ aWinRect.right = width-1;
+ aWinRect.top = 0;
+ aWinRect.bottom = height-1;
+ AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ),
+ FALSE, GetWindowExStyle( pFrame->mhWnd ) );
+ width = aWinRect.right - aWinRect.left + 1;
+ height = aWinRect.bottom - aWinRect.top + 1;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame,
+ int& rX, int& rY, int& rDX, int& rDY )
+{
+ // set window to screen size
+ int nFrameX;
+ int nFrameY;
+ int nCaptionY;
+ int nScreenX = 0;
+ int nScreenY = 0;
+ int nScreenDX = 0;
+ int nScreenDY = 0;
+
+ if ( pFrame->mbSizeBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXSIZEFRAME );
+ nFrameY = GetSystemMetrics( SM_CYSIZEFRAME );
+ }
+ else if ( pFrame->mbFixBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME );
+ nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME );
+ }
+ else if ( pFrame->mbBorder )
+ {
+ nFrameX = GetSystemMetrics( SM_CXBORDER );
+ nFrameY = GetSystemMetrics( SM_CYBORDER );
+ }
+ else
+ {
+ nFrameX = 0;
+ nFrameY = 0;
+ }
+ if ( pFrame->mbCaption )
+ nCaptionY = GetSystemMetrics( SM_CYCAPTION );
+ else
+ nCaptionY = 0;
+
+ try
+ {
+ uno::Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW );
+ uno::Reference< XIndexAccess > xMultiMon( xFactory->createInstance(OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) ) ), UNO_QUERY_THROW );
+ if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < xMultiMon->getCount()) )
+ {
+ uno::Reference< XPropertySet > xMonitor( xMultiMon->getByIndex( pFrame->mnDisplay ), UNO_QUERY_THROW );
+ com::sun::star::awt::Rectangle aRect;
+ if( xMonitor->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "ScreenArea" ) ) ) >>= aRect )
+ {
+ nScreenX = aRect.X;
+ nScreenY = aRect.Y;
+ nScreenDX = aRect.Width+1; // difference between java/awt convention and vcl
+ nScreenDY = aRect.Height+1; // difference between java/awt convention and vcl
+ }
+ }
+ else
+ {
+ nScreenX = GetSystemMetrics( SM_XVIRTUALSCREEN );
+ nScreenY = GetSystemMetrics( SM_YVIRTUALSCREEN );
+ nScreenDX = GetSystemMetrics( SM_CXVIRTUALSCREEN );
+ nScreenDY = GetSystemMetrics( SM_CYVIRTUALSCREEN );
+ }
+ }
+ catch( Exception& )
+ {
+ }
+
+ if( !nScreenDX || !nScreenDY )
+ {
+ nScreenDX = GetSystemMetrics( SM_CXSCREEN );
+ nScreenDY = GetSystemMetrics( SM_CYSCREEN );
+ }
+
+ rX = nScreenX -nFrameX;
+ rY = nScreenY -(nFrameY+nCaptionY);
+ rDX = nScreenDX+(nFrameX*2);
+ rDY = nScreenDY+(nFrameY*2)+nCaptionY;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, sal_Bool bAlways = FALSE )
+{
+ if ( bAlways || !IsIconic( pFrame->mhWnd ) )
+ {
+ // set window to screen size
+ int nX;
+ int nY;
+ int nWidth;
+ int nHeight;
+ ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
+ SetWindowPos( pFrame->mhWnd, 0,
+ nX, nY, nWidth, nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame::WinSalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ mhWnd = 0;
+ mhCursor = LoadCursor( 0, IDC_ARROW );
+ mhDefIMEContext = 0;
+ mpGraphics = NULL;
+ mpGraphics2 = NULL;
+ mnShowState = SW_SHOWNORMAL;
+ mnWidth = 0;
+ mnHeight = 0;
+ mnMinWidth = 0;
+ mnMinHeight = 0;
+ mnMaxWidth = SHRT_MAX;
+ mnMaxHeight = SHRT_MAX;
+ mnInputLang = 0;
+ mnInputCodePage = 0;
+ mbGraphics = FALSE;
+ mbCaption = FALSE;
+ mbBorder = FALSE;
+ mbFixBorder = FALSE;
+ mbSizeBorder = FALSE;
+ mbFullScreen = FALSE;
+ mbPresentation = FALSE;
+ mbInShow = FALSE;
+ mbRestoreMaximize = FALSE;
+ mbInMoveMsg = FALSE;
+ mbInSizeMsg = FALSE;
+ mbFullScreenToolWin = FALSE;
+ mbDefPos = TRUE;
+ mbOverwriteState = TRUE;
+ mbIME = FALSE;
+ mbHandleIME = FALSE;
+ mbSpezIME = FALSE;
+ mbAtCursorIME = FALSE;
+ mbCandidateMode = FALSE;
+ mbFloatWin = FALSE;
+ mbNoIcon = FALSE;
+ mSelectedhMenu = 0;
+ mLastActivatedhMenu = 0;
+ mpClipRgnData = NULL;
+ mbFirstClipRect = TRUE;
+ mpNextClipRect = NULL;
+ mnDisplay = 0;
+
+ memset( &maState, 0, sizeof( SalFrameState ) );
+ maSysData.nSize = sizeof( SystemEnvData );
+
+ memset( &maGeometry, 0, sizeof( maGeometry ) );
+
+ // Daten ermitteln, wenn erster Frame angelegt wird
+ if ( !pSalData->mpFirstFrame )
+ {
+ if ( !aSalShlData.mnWheelMsgId )
+ aSalShlData.mnWheelMsgId = RegisterWindowMessage( MSH_MOUSEWHEEL );
+ if ( !aSalShlData.mnWheelScrollLines )
+ aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
+ if ( !aSalShlData.mnWheelScrollChars )
+ aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+ }
+
+ // insert frame in framelist
+ mpNextFrame = pSalData->mpFirstFrame;
+ pSalData->mpFirstFrame = this;
+}
+
+// -----------------------------------------------------------------------
+void WinSalFrame::updateScreenNumber()
+{
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ {
+ const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
+ pSys->getMonitors();
+ Point aPoint( maGeometry.nX, maGeometry.nY );
+ size_t nMon = rMonitors.size();
+ for( size_t i = 0; i < nMon; i++ )
+ {
+ if( rMonitors[i].m_aArea.IsInside( aPoint ) )
+ {
+ mnDisplay = static_cast<sal_Int32>(i);
+ maGeometry.nScreenNumber = static_cast<unsigned int>(i);
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame::~WinSalFrame()
+{
+ SalData* pSalData = GetSalData();
+
+ if( mpClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+
+ // remove frame from framelist
+ WinSalFrame** ppFrame = &pSalData->mpFirstFrame;
+ for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame );
+ if( *ppFrame )
+ *ppFrame = mpNextFrame;
+ mpNextFrame = NULL;
+
+ // Release Cache DC
+ if ( mpGraphics2 &&
+ mpGraphics2->mhDC )
+ ReleaseGraphics( mpGraphics2 );
+
+ // destroy saved DC
+ if ( mpGraphics )
+ {
+ if ( mpGraphics->mhDefPal )
+ SelectPalette( mpGraphics->mhDC, mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics );
+ ReleaseDC( mhWnd, mpGraphics->mhDC );
+ delete mpGraphics;
+ mpGraphics = NULL;
+ }
+
+ if ( mhWnd )
+ {
+ // reset mouse leave data
+ if ( pSalData->mhWantLeaveMsg == mhWnd )
+ {
+ pSalData->mhWantLeaveMsg = 0;
+ if ( pSalData->mpMouseLeaveTimer )
+ {
+ delete pSalData->mpMouseLeaveTimer;
+ pSalData->mpMouseLeaveTimer = NULL;
+ }
+ }
+
+ // destroy system frame
+ if ( !DestroyWindow( mhWnd ) )
+ SetWindowPtr( mhWnd, 0 );
+
+ mhWnd = 0;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+SalGraphics* WinSalFrame::GetGraphics()
+{
+ if ( mbGraphics )
+ return NULL;
+
+ // Other threads get an own DC, because Windows modify in the
+ // other case our DC (changing clip region), when they send a
+ // WM_ERASEBACKGROUND message
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
+ {
+ // We use only three CacheDC's for all threads, because W9x is limited
+ // to max. 5 Cache DC's per thread
+ if ( pSalData->mnCacheDCInUse >= 3 )
+ return NULL;
+
+ if ( !mpGraphics2 )
+ {
+ mpGraphics2 = new WinSalGraphics;
+ mpGraphics2->mhDC = 0;
+ mpGraphics2->mhWnd = mhWnd;
+ mpGraphics2->mbPrinter = FALSE;
+ mpGraphics2->mbVirDev = FALSE;
+ mpGraphics2->mbWindow = TRUE;
+ mpGraphics2->mbScreen = TRUE;
+ }
+
+ HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_GETDC,
+ (WPARAM)mhWnd, 0 );
+ if ( hDC )
+ {
+ mpGraphics2->mhDC = hDC;
+ if ( pSalData->mhDitherPal )
+ {
+ mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( mpGraphics2 );
+ mbGraphics = TRUE;
+
+ pSalData->mnCacheDCInUse++;
+ return mpGraphics2;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ if ( !mpGraphics )
+ {
+ HDC hDC = GetDC( mhWnd );
+ if ( hDC )
+ {
+ mpGraphics = new WinSalGraphics;
+ mpGraphics->mhDC = hDC;
+ mpGraphics->mhWnd = mhWnd;
+ mpGraphics->mbPrinter = FALSE;
+ mpGraphics->mbVirDev = FALSE;
+ mpGraphics->mbWindow = TRUE;
+ mpGraphics->mbScreen = TRUE;
+ if ( pSalData->mhDitherPal )
+ {
+ mpGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( mpGraphics );
+ mbGraphics = TRUE;
+ }
+ }
+ else
+ mbGraphics = TRUE;
+
+ return mpGraphics;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
+{
+ if ( mpGraphics2 == pGraphics )
+ {
+ if ( mpGraphics2->mhDC )
+ {
+ SalData* pSalData = GetSalData();
+ if ( mpGraphics2->mhDefPal )
+ SelectPalette( mpGraphics2->mhDC, mpGraphics2->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( mpGraphics2 );
+ ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_RELEASEDC,
+ (WPARAM)mhWnd,
+ (LPARAM)mpGraphics2->mhDC );
+ mpGraphics2->mhDC = 0;
+ pSalData->mnCacheDCInUse--;
+ }
+ }
+
+ mbGraphics = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalFrame::PostEvent( void* pData )
+{
+ return (sal_Bool)ImplPostMessage( mhWnd, SAL_MSG_USEREVENT, 0, (LPARAM)pData );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetTitle( const XubString& rTitle )
+{
+ DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::SetTitle(): WCHAR != sal_Unicode" );
+
+ if ( !SetWindowTextW( mhWnd, reinterpret_cast<LPCWSTR>(rTitle.GetBuffer()) ) )
+ {
+ ByteString aAnsiTitle = ImplSalGetWinAnsiString( rTitle );
+ SetWindowTextA( mhWnd, aAnsiTitle.GetBuffer() );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetIcon( sal_uInt16 nIcon )
+{
+ // If we have a window without an Icon (for example a dialog), ignore this call
+ if ( mbNoIcon )
+ return;
+
+ // 0 means default (class) icon
+ HICON hIcon = NULL, hSmIcon = NULL;
+ if ( !nIcon )
+ nIcon = 1;
+
+ ImplLoadSalIcon( nIcon, hIcon, hSmIcon );
+
+ DBG_ASSERT( hIcon , "WinSalFrame::SetIcon(): Could not load large icon !" );
+ DBG_ASSERT( hSmIcon , "WinSalFrame::SetIcon(): Could not load small icon !" );
+
+ ImplSendMessage( mhWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon );
+ ImplSendMessage( mhWnd, WM_SETICON, ICON_SMALL, (LPARAM)hSmIcon );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetMenu( SalMenu* pSalMenu )
+{
+ WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu);
+ if( pSalMenu && pWMenu->mbMenuBar )
+ ::SetMenu( mhWnd, pWMenu->mhMenu );
+}
+
+void WinSalFrame::DrawMenuBar()
+{
+ ::DrawMenuBar( mhWnd );
+}
+
+// -----------------------------------------------------------------------
+HWND ImplGetParentHwnd( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if( !pFrame || !pFrame->GetWindow())
+ return ::GetParent( hWnd );
+ Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent;
+ if( pRealParent )
+ return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd;
+ else
+ return ::GetParent( hWnd );
+
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame* WinSalFrame::GetParent() const
+{
+ return GetWindowPtr( ImplGetParentHwnd( mhWnd ) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalShow( HWND hWnd, sal_Bool bVisible, sal_Bool bNoActivate )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return;
+
+ if ( bVisible )
+ {
+ pFrame->mbDefPos = FALSE;
+ pFrame->mbOverwriteState = TRUE;
+ pFrame->mbInShow = TRUE;
+
+ // #i4715, save position
+ RECT aRectPreMatrox, aRectPostMatrox;
+ GetWindowRect( hWnd, &aRectPreMatrox );
+
+ vcl::DeletionListener aDogTag( pFrame );
+ if( bNoActivate )
+ ShowWindow( hWnd, SW_SHOWNOACTIVATE );
+ else
+ ShowWindow( hWnd, pFrame->mnShowState );
+ if( aDogTag.isDeleted() )
+ return;
+
+ if ( aSalShlData.mbWXP && pFrame->mbFloatWin && !(pFrame->mnStyle & SAL_FRAME_STYLE_NOSHADOW))
+ {
+ // erase the window immediately to improve XP shadow effect
+ // otherwise the shadow may appears long time before the rest of the window
+ // especially when accessibility is on
+ HDC dc = GetDC( hWnd );
+ RECT aRect;
+ GetClientRect( hWnd, &aRect );
+ FillRect( dc, &aRect, (HBRUSH) (COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menues
+ ReleaseDC( hWnd, dc );
+ }
+
+ // #i4715, matrox centerpopup might have changed our position
+ // reposition popups without caption (menues, dropdowns, tooltips)
+ GetWindowRect( hWnd, &aRectPostMatrox );
+ if( (GetWindowStyle( hWnd ) & WS_POPUP) &&
+ !pFrame->mbCaption &&
+ (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) )
+ SetWindowPos( hWnd, 0, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
+
+ if( aDogTag.isDeleted() )
+ return;
+ Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow();
+ if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
+ pFrame->mnShowState = SW_SHOWNOACTIVATE;
+ else
+ pFrame->mnShowState = SW_SHOW;
+ // Damit Taskleiste unter W98 auch gleich ausgeblendet wird
+ if ( pFrame->mbPresentation )
+ {
+ HWND hWndParent = ::GetParent( hWnd );
+ if ( hWndParent )
+ SetForegroundWindow( hWndParent );
+ SetForegroundWindow( hWnd );
+ }
+
+ pFrame->mbInShow = FALSE;
+ pFrame->updateScreenNumber();
+
+ // Direct Paint only, if we get the SolarMutx
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ UpdateWindow( hWnd );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ else
+ {
+ // See also Bug #91813# and #68467#
+ if ( pFrame->mbFullScreen &&
+ pFrame->mbPresentation &&
+ (aSalShlData.mnVersion < 500) &&
+ !::GetParent( hWnd ) )
+ {
+ // Damit im Impress-Player in der Taskleiste nicht durch
+ // einen Windows-Fehler hin- und wieder mal ein leerer
+ // Button stehen bleibt, muessen wir hier die Taskleiste
+ // etwas austricksen. Denn wenn wir im FullScreenMode sind
+ // und das Fenster hiden kommt Windows anscheinend etwas aus
+ // dem tritt und somit minimieren wir das Fenster damit es
+ // nicht flackert
+ ANIMATIONINFO aInfo;
+ aInfo.cbSize = sizeof( aInfo );
+ SystemParametersInfo( SPI_GETANIMATION, 0, &aInfo, 0 );
+ if ( aInfo.iMinAnimate )
+ {
+ int nOldAni = aInfo.iMinAnimate;
+ aInfo.iMinAnimate = 0;
+ SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 );
+ ShowWindow( pFrame->mhWnd, SW_SHOWMINNOACTIVE );
+ aInfo.iMinAnimate = nOldAni;
+ SystemParametersInfo( SPI_SETANIMATION, 0, &aInfo, 0 );
+ }
+ else
+ ShowWindow( hWnd, SW_SHOWMINNOACTIVE );
+ ShowWindow( hWnd, SW_HIDE );
+ }
+ else
+ ShowWindow( hWnd, SW_HIDE );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+
+void WinSalFrame::SetExtendedFrameStyle( SalExtStyle )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Show( sal_Bool bVisible, sal_Bool bNoActivate )
+{
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( mhWnd, SAL_MSG_SHOW, bVisible, bNoActivate );
+ else
+ ImplSalShow( mhWnd, bVisible, bNoActivate );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Enable( sal_Bool bEnable )
+{
+ EnableWindow( mhWnd, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetMinClientSize( long nWidth, long nHeight )
+{
+ mnMinWidth = nWidth;
+ mnMinHeight = nHeight;
+}
+
+void WinSalFrame::SetMaxClientSize( long nWidth, long nHeight )
+{
+ mnMaxWidth = nWidth;
+ mnMaxHeight = nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight,
+ sal_uInt16 nFlags )
+{
+ sal_Bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( !bVisible )
+ {
+ Window *pClientWin = GetWindow()->ImplGetClientWindow();
+ if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
+ mnShowState = SW_SHOWNOACTIVATE;
+ else
+ mnShowState = SW_SHOWNORMAL;
+ }
+ else
+ {
+ if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) )
+ ShowWindow( mhWnd, SW_RESTORE );
+ }
+
+ sal_uInt16 nEvent = 0;
+ UINT nPosSize = 0;
+ RECT aClientRect, aWindowRect;
+ GetClientRect( mhWnd, &aClientRect ); // x,y always 0,0, but width and height without border
+ GetWindowRect( mhWnd, &aWindowRect ); // x,y in screen coordinates, width and height with border
+
+ if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) )
+ nPosSize |= SWP_NOMOVE;
+ else
+ {
+ //DBG_ASSERT( nX && nY, " Windowposition of (0,0) requested!" );
+ nEvent = SALEVENT_MOVE;
+ }
+ if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) )
+ nPosSize |= SWP_NOSIZE;
+ else
+ nEvent = (nEvent == SALEVENT_MOVE) ? SALEVENT_MOVERESIZE : SALEVENT_RESIZE;
+
+ if ( !(nFlags & SAL_FRAME_POSSIZE_X) )
+ nX = aWindowRect.left;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_Y) )
+ nY = aWindowRect.top;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) )
+ nWidth = aClientRect.right-aClientRect.left;
+ if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) )
+ nHeight = aClientRect.bottom-aClientRect.top;
+
+ // Calculate window size including the border
+ RECT aWinRect;
+ aWinRect.left = 0;
+ aWinRect.right = (int)nWidth-1;
+ aWinRect.top = 0;
+ aWinRect.bottom = (int)nHeight-1;
+ AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ),
+ FALSE, GetWindowExStyle( mhWnd ) );
+ nWidth = aWinRect.right - aWinRect.left + 1;
+ nHeight = aWinRect.bottom - aWinRect.top + 1;
+
+ if ( !(nPosSize & SWP_NOMOVE) && ::GetParent( mhWnd ) )
+ {
+ // --- RTL --- (mirror window pos)
+ RECT aParentRect;
+ GetClientRect( ImplGetParentHwnd( mhWnd ), &aParentRect );
+ if( Application::GetSettings().GetLayoutRTL() )
+ nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX;
+
+ //#110386#, do not transform coordinates for system child windows
+ if( !(GetWindowStyle( mhWnd ) & WS_CHILD) )
+ {
+ POINT aPt;
+ aPt.x = nX;
+ aPt.y = nY;
+
+ HWND parentHwnd = ImplGetParentHwnd( mhWnd );
+ WinSalFrame* pParentFrame = GetWindowPtr( parentHwnd );
+ if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED )
+ {
+ // #i42485#: parent will be shown maximized in which case
+ // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos)
+ // so use the (already updated) frame geometry for the transformation
+ aPt.x += pParentFrame->maGeometry.nX;
+ aPt.y += pParentFrame->maGeometry.nY;
+ }
+ else
+ ClientToScreen( parentHwnd, &aPt );
+
+ nX = aPt.x;
+ nY = aPt.y;
+ }
+ }
+
+ // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration
+ // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified
+ if ( nFlags & SAL_FRAME_POSSIZE_X )
+ nX += aWinRect.left;
+ if ( nFlags & SAL_FRAME_POSSIZE_Y )
+ nY += aWinRect.top;
+
+ int nScreenX;
+ int nScreenY;
+ int nScreenWidth;
+ int nScreenHeight;
+
+
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ nScreenX = aRect.left;
+ nScreenY = aRect.top;
+ nScreenWidth = aRect.right-aRect.left;
+ nScreenHeight = aRect.bottom-aRect.top;
+
+ if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position
+ {
+ // center window
+
+ HWND hWndParent = ::GetParent( mhWnd );
+ // Search for TopLevel Frame
+ while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_CHILD) )
+ hWndParent = ::GetParent( hWndParent );
+ // if the Window has a Parent, than center the window to
+ // the parent, in the other case to the screen
+ if ( hWndParent && !IsIconic( hWndParent ) &&
+ (GetWindowStyle( hWndParent ) & WS_VISIBLE) )
+ {
+ RECT aParentRect;
+ GetWindowRect( hWndParent, &aParentRect );
+ int nParentWidth = aParentRect.right-aParentRect.left;
+ int nParentHeight = aParentRect.bottom-aParentRect.top;
+
+ // We don't center, when Parent is smaller than our window
+ if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) &&
+ (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) )
+ {
+ int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
+ nX = aParentRect.left+nOff;
+ nY = aParentRect.top+nOff;
+ }
+ else
+ {
+ nX = (nParentWidth-nWidth)/2 + aParentRect.left;
+ nY = (nParentHeight-nHeight)/2 + aParentRect.top;
+ }
+ }
+ else
+ {
+ POINT pt;
+ GetCursorPos( &pt );
+ RECT aRect;
+ aRect.left = pt.x;
+ aRect.top = pt.y;
+ aRect.right = pt.x+2;
+ aRect.bottom = pt.y+2;
+
+ // dualmonitor support:
+ // Get screensize of the monitor whith the mouse pointer
+ ImplSalGetWorkArea( mhWnd, &aRect, &aRect );
+
+ nX = ((aRect.right-aRect.left)-nWidth)/2 + aRect.left;
+ nY = ((aRect.bottom-aRect.top)-nHeight)/2 + aRect.top;
+ }
+
+
+ //if ( bVisible )
+ // mbDefPos = FALSE;
+
+ mbDefPos = FALSE; // center only once
+ nPosSize &= ~SWP_NOMOVE; // activate positioning
+ nEvent = SALEVENT_MOVERESIZE;
+ }
+
+
+ // Adjust Window in the screen
+ sal_Bool bCheckOffScreen = TRUE;
+
+ // but don't do this for floaters or ownerdraw windows that are currently moved interactively
+ if( (mnStyle & SAL_FRAME_STYLE_FLOAT) && !(mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION) )
+ bCheckOffScreen = FALSE;
+
+ if( mnStyle & SAL_FRAME_STYLE_OWNERDRAWDECORATION )
+ {
+ // may be the window is currently being moved (mouse is captured), then no check is required
+ if( mhWnd == ::GetCapture() )
+ bCheckOffScreen = FALSE;
+ else
+ bCheckOffScreen = TRUE;
+ }
+
+ if( bCheckOffScreen )
+ {
+ if ( nX+nWidth > nScreenX+nScreenWidth )
+ nX = (nScreenX+nScreenWidth) - nWidth;
+ if ( nY+nHeight > nScreenY+nScreenHeight )
+ nY = (nScreenY+nScreenHeight) - nHeight;
+ if ( nX < nScreenX )
+ nX = nScreenX;
+ if ( nY < nScreenY )
+ nY = nScreenY;
+ }
+
+ UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize;
+ // bring floating windows always to top
+ if( !(mnStyle & SAL_FRAME_STYLE_FLOAT) )
+ nPosFlags |= SWP_NOZORDER; // do not change z-order
+
+ SetWindowPos( mhWnd, HWND_TOP, nX, nY, (int)nWidth, (int)nHeight, nPosFlags );
+
+ UpdateFrameGeometry( mhWnd, this );
+
+ // Notification -- really ???
+ if( nEvent )
+ CallCallback( nEvent, NULL );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, sal_Bool bAsChild )
+{
+ // save hwnd, will be overwritten in WM_CREATE during createwindow
+ HWND hWndOld = pThis->mhWnd;
+ HWND hWndOldParent = ::GetParent( hWndOld );
+ SalData* pSalData = GetSalData();
+
+ if( hNewParentWnd == hWndOldParent )
+ return;
+
+ ::std::vector< WinSalFrame* > children;
+ ::std::vector< WinSalObject* > systemChildren;
+
+ // search child windows
+ WinSalFrame *pFrame = pSalData->mpFirstFrame;
+ while( pFrame )
+ {
+ HWND hWndParent = ::GetParent( pFrame->mhWnd );
+ if( pThis->mhWnd == hWndParent )
+ children.push_back( pFrame );
+ pFrame = pFrame->mpNextFrame;
+ }
+
+ // search system child windows (plugins etc.)
+ WinSalObject *pObject = pSalData->mpFirstObject;
+ while( pObject )
+ {
+ HWND hWndParent = ::GetParent( pObject->mhWnd );
+ if( pThis->mhWnd == hWndParent )
+ systemChildren.push_back( pObject );
+ pObject = pObject->mpNextObject;
+ }
+
+ sal_Bool bNeedGraphics = pThis->mbGraphics;
+ sal_Bool bNeedCacheDC = FALSE;
+
+ HFONT hFont = NULL;
+ HPEN hPen = NULL;
+ HBRUSH hBrush = NULL;
+
+ #if OSL_DEBUG_LEVEL > 0
+ int oldCount = pSalData->mnCacheDCInUse;
+ (void)oldCount;
+ #endif
+
+ // Release Cache DC
+ if ( pThis->mpGraphics2 &&
+ pThis->mpGraphics2->mhDC )
+ {
+ // save current gdi objects before hdc is gone
+ hFont = (HFONT) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_FONT);
+ hPen = (HPEN) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_PEN);
+ hBrush = (HBRUSH) GetCurrentObject( pThis->mpGraphics2->mhDC, OBJ_BRUSH);
+ pThis->ReleaseGraphics( pThis->mpGraphics2 );
+
+ // recreate cache dc only if it was destroyed
+ bNeedCacheDC = TRUE;
+ }
+
+ // destroy saved DC
+ if ( pThis->mpGraphics )
+ {
+ if ( pThis->mpGraphics->mhDefPal )
+ SelectPalette( pThis->mpGraphics->mhDC, pThis->mpGraphics->mhDefPal, TRUE );
+ ImplSalDeInitGraphics( pThis->mpGraphics );
+ ReleaseDC( pThis->mhWnd, pThis->mpGraphics->mhDC );
+ }
+
+ // create a new hwnd with the same styles
+ HWND hWndParent = hNewParentWnd;
+ // forward to main thread
+ HWND hWnd = (HWND) ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND,
+ (WPARAM) hWndParent, (LPARAM)pThis->mhWnd );
+
+ // succeeded ?
+ DBG_ASSERT( IsWindow( hWnd ), "WinSalFrame::SetParent not successful");
+
+ // recreate DCs
+ if( bNeedGraphics )
+ {
+ if( pThis->mpGraphics2 )
+ {
+ pThis->mpGraphics2->mhWnd = hWnd;
+
+ if( bNeedCacheDC )
+ {
+ // re-create cached DC
+ HDC hDC = (HDC)ImplSendMessage( pSalData->mpFirstInstance->mhComWnd,
+ SAL_MSG_GETDC,
+ (WPARAM) hWnd, 0 );
+ if ( hDC )
+ {
+ pThis->mpGraphics2->mhDC = hDC;
+ if ( pSalData->mhDitherPal )
+ {
+ pThis->mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE );
+ RealizePalette( hDC );
+ }
+ ImplSalInitGraphics( pThis->mpGraphics2 );
+
+ // re-select saved gdi objects
+ if( hFont )
+ SelectObject( hDC, hFont );
+ if( hPen )
+ SelectObject( hDC, hPen );
+ if( hBrush )
+ SelectObject( hDC, hBrush );
+
+ pThis->mbGraphics = TRUE;
+
+ pSalData->mnCacheDCInUse++;
+
+ DBG_ASSERT( oldCount == pSalData->mnCacheDCInUse, "WinSalFrame::SetParent() hDC count corrupted");
+ }
+ }
+ }
+
+ if( pThis->mpGraphics )
+ {
+ // re-create DC
+ pThis->mpGraphics->mhWnd = hWnd;
+ pThis->mpGraphics->mhDC = GetDC( hWnd );
+ if ( GetSalData()->mhDitherPal )
+ {
+ pThis->mpGraphics->mhDefPal = SelectPalette( pThis->mpGraphics->mhDC, GetSalData()->mhDitherPal, TRUE );
+ RealizePalette( pThis->mpGraphics->mhDC );
+ }
+ ImplSalInitGraphics( pThis->mpGraphics );
+ pThis->mbGraphics = TRUE;
+ }
+ }
+
+
+ // TODO: add SetParent() call for SalObjects
+ DBG_ASSERT( systemChildren.empty(), "WinSalFrame::SetParent() parent of living system child window will be destroyed!");
+
+ // reparent children before old parent is destroyed
+ for( ::std::vector< WinSalFrame* >::iterator iChild = children.begin(); iChild != children.end(); iChild++ )
+ ImplSetParentFrame( *iChild, hWnd, FALSE );
+
+ children.clear();
+ systemChildren.clear();
+
+ // Now destroy original HWND in the thread where it was created.
+ ImplSendMessage( GetSalData()->mpFirstInstance->mhComWnd,
+ SAL_MSG_DESTROYHWND, (WPARAM) 0, (LPARAM)hWndOld);
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetParent( SalFrame* pNewParent )
+{
+ WinSalFrame::mbInReparent = TRUE;
+ ImplSetParentFrame( this, static_cast<WinSalFrame*>(pNewParent)->mhWnd, FALSE );
+ WinSalFrame::mbInReparent = FALSE;
+}
+
+bool WinSalFrame::SetPluginParent( SystemParentData* pNewParent )
+{
+ if ( pNewParent->hWnd == 0 )
+ {
+ pNewParent->hWnd = GetDesktopWindow();
+ }
+
+ WinSalFrame::mbInReparent = TRUE;
+ ImplSetParentFrame( this, pNewParent->hWnd, TRUE );
+ WinSalFrame::mbInReparent = FALSE;
+ return true;
+}
+
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::GetWorkArea( Rectangle &rRect )
+{
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ rRect.nLeft = aRect.left;
+ rRect.nRight = aRect.right-1;
+ rRect.nTop = aRect.top;
+ rRect.nBottom = aRect.bottom-1;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::GetClientSize( long& rWidth, long& rHeight )
+{
+ rWidth = maGeometry.nWidth;
+ rHeight = maGeometry.nHeight;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetWindowState( const SalFrameState* pState )
+{
+ // Wir testen, ob das Fenster ueberhaupt auf den Bildschirm passt, damit
+ // nicht wenn die Bildschirm-Aufloesung geaendert wurde, das Fenster aus
+ // diesem herausragt
+ int nX;
+ int nY;
+ int nWidth;
+ int nHeight;
+ int nScreenX;
+ int nScreenY;
+ int nScreenWidth;
+ int nScreenHeight;
+
+ RECT aRect;
+ ImplSalGetWorkArea( mhWnd, &aRect, NULL );
+ // #102500# allow some overlap, the window could have been made a little larger than the physical screen
+ nScreenX = aRect.left-10;
+ nScreenY = aRect.top-10;
+ nScreenWidth = aRect.right-aRect.left+20;
+ nScreenHeight = aRect.bottom-aRect.top+20;
+
+ UINT nPosSize = 0;
+ RECT aWinRect;
+ GetWindowRect( mhWnd, &aWinRect );
+
+ // to be consistent with Unix, the frame state is without(!) decoration
+ // ->add the decoration
+ RECT aRect2 = aWinRect;
+ AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ),
+ FALSE, GetWindowExStyle( mhWnd ) );
+ long nTopDeco = abs( aWinRect.top - aRect2.top );
+ long nLeftDeco = abs( aWinRect.left - aRect2.left );
+ long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom );
+ long nRightDeco = abs( aWinRect.right - aRect2.right );
+
+ // Fenster-Position/Groesse in den Bildschirm einpassen
+ if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_X | SAL_FRAMESTATE_MASK_Y)) )
+ nPosSize |= SWP_NOMOVE;
+ if ( !(pState->mnMask & (SAL_FRAMESTATE_MASK_WIDTH | SAL_FRAMESTATE_MASK_HEIGHT)) )
+ nPosSize |= SWP_NOSIZE;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_X )
+ nX = (int)pState->mnX - nLeftDeco;
+ else
+ nX = aWinRect.left;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_Y )
+ nY = (int)pState->mnY - nTopDeco;
+ else
+ nY = aWinRect.top;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_WIDTH )
+ nWidth = (int)pState->mnWidth + nLeftDeco + nRightDeco;
+ else
+ nWidth = aWinRect.right-aWinRect.left;
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_HEIGHT )
+ nHeight = (int)pState->mnHeight + nTopDeco + nBottomDeco;
+ else
+ nHeight = aWinRect.bottom-aWinRect.top;
+
+ // Adjust Window in the screen:
+ // if it does not fit into the screen do nothing, ie default pos/size will be used
+ // if there is an overlap with the screen border move the window while keeping its size
+
+ if( nWidth > nScreenWidth || nHeight > nScreenHeight )
+ nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
+
+ if ( nX+nWidth > nScreenX+nScreenWidth )
+ nX = (nScreenX+nScreenWidth) - nWidth;
+ if ( nY+nHeight > nScreenY+nScreenHeight )
+ nY = (nScreenY+nScreenHeight) - nHeight;
+ if ( nX < nScreenX )
+ nX = nScreenX;
+ if ( nY < nScreenY )
+ nY = nScreenY;
+
+ // Restore-Position setzen
+ WINDOWPLACEMENT aPlacement;
+ aPlacement.length = sizeof( aPlacement );
+ GetWindowPlacement( mhWnd, &aPlacement );
+
+ // Status setzen
+ sal_Bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ sal_Bool bUpdateHiddenFramePos = FALSE;
+ if ( !bVisible )
+ {
+ aPlacement.showCmd = SW_HIDE;
+
+ if ( mbOverwriteState )
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ mnShowState = SW_SHOWMINIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ {
+ mnShowState = SW_SHOWMAXIMIZED;
+ bUpdateHiddenFramePos = TRUE;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ mnShowState = SW_SHOWNORMAL;
+ }
+ }
+ }
+ else
+ {
+ if ( pState->mnMask & SAL_FRAMESTATE_MASK_STATE )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MINIMIZED )
+ {
+ if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
+ aPlacement.showCmd = SW_SHOWMINIMIZED;
+ }
+ else if ( pState->mnState & SAL_FRAMESTATE_MAXIMIZED )
+ aPlacement.showCmd = SW_SHOWMAXIMIZED;
+ else if ( pState->mnState & SAL_FRAMESTATE_NORMAL )
+ aPlacement.showCmd = SW_RESTORE;
+ }
+ }
+
+ // if a window is neither minimized nor maximized or need not be
+ // positioned visibly (that is in visible state), do not use
+ // SetWindowPlacement since it calculates including the TaskBar
+ if ( !IsIconic( mhWnd ) && !IsZoomed( mhWnd ) &&
+ (!bVisible || (aPlacement.showCmd == SW_RESTORE)) )
+ {
+ if( bUpdateHiddenFramePos )
+ {
+ RECT aStateRect;
+ aStateRect.left = nX;
+ aStateRect.top = nY;
+ aStateRect.right = nX+nWidth;
+ aStateRect.bottom = nY+nHeight;
+ // #96084 set a useful internal window size because
+ // the window will not be maximized (and the size updated) before show()
+ SetMaximizedFrameGeometry( mhWnd, this, &aStateRect );
+ SetWindowPos( mhWnd, 0,
+ maGeometry.nX, maGeometry.nY, maGeometry.nWidth, maGeometry.nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
+ }
+ else
+ SetWindowPos( mhWnd, 0,
+ nX, nY, nWidth, nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
+ }
+ else
+ {
+ if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) )
+ {
+ aPlacement.rcNormalPosition.left = nX-nScreenX;
+ aPlacement.rcNormalPosition.top = nY-nScreenY;
+ aPlacement.rcNormalPosition.right = nX+nWidth-nScreenX;
+ aPlacement.rcNormalPosition.bottom = nY+nHeight-nScreenY;
+ }
+ SetWindowPlacement( mhWnd, &aPlacement );
+ }
+
+ if( !(nPosSize & SWP_NOMOVE) )
+ mbDefPos = FALSE; // window was positioned
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalFrame::GetWindowState( SalFrameState* pState )
+{
+ if ( maState.mnWidth && maState.mnHeight )
+ {
+ *pState = maState;
+ // #94144# allow Minimize again, should be masked out when read from configuration
+ // 91625 - Don't save minimize
+ //if ( !(pState->mnState & SAL_FRAMESTATE_MAXIMIZED) )
+ if ( !(pState->mnState & (SAL_FRAMESTATE_MINIMIZED | SAL_FRAMESTATE_MAXIMIZED)) )
+ pState->mnState |= SAL_FRAMESTATE_NORMAL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetScreenNumber( unsigned int nNewScreen )
+{
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ {
+ const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
+ pSys->getMonitors();
+ size_t nMon = rMonitors.size();
+ if( nNewScreen < nMon )
+ {
+ Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
+ Point aCurPos( maGeometry.nX, maGeometry.nY );
+ for( size_t i = 0; i < nMon; i++ )
+ {
+ if( rMonitors[i].m_aArea.IsInside( aCurPos ) )
+ {
+ aOldMonPos = rMonitors[i].m_aArea.TopLeft();
+ break;
+ }
+ }
+ mnDisplay = nNewScreen;
+ maGeometry.nScreenNumber = nNewScreen;
+ SetPosSize( aNewMonPos.X() + (maGeometry.nX - aOldMonPos.X()),
+ aNewMonPos.Y() + (maGeometry.nY - aOldMonPos.Y()),
+ 0, 0,
+ SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ShowFullScreen( sal_Bool bFullScreen, sal_Int32 nDisplay )
+{
+ if ( (mbFullScreen == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)) )
+ return;
+
+ mbFullScreen = bFullScreen;
+ mnDisplay = nDisplay;
+
+ if ( bFullScreen )
+ {
+ // Damit Taskleiste von Windows ausgeblendet wird
+ DWORD nExStyle = GetWindowExStyle( mhWnd );
+ if ( nExStyle & WS_EX_TOOLWINDOW )
+ {
+ mbFullScreenToolWin = TRUE;
+ nExStyle &= ~WS_EX_TOOLWINDOW;
+ SetWindowExStyle( mhWnd, nExStyle );
+ }
+ // save old position
+ GetWindowRect( mhWnd, &maFullScreenRect );
+
+ // save show state
+ mnFullScreenShowState = mnShowState;
+ if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
+ mnShowState = SW_SHOW;
+
+ // set window to screen size
+ ImplSalFrameFullScreenPos( this, TRUE );
+ }
+ else
+ {
+ // wenn ShowState wieder hergestellt werden muss, hiden wir zuerst
+ // das Fenster, damit es nicht so sehr flackert
+ sal_Bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( bVisible && (mnShowState != mnFullScreenShowState) )
+ ShowWindow( mhWnd, SW_HIDE );
+
+ if ( mbFullScreenToolWin )
+ SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW );
+ mbFullScreenToolWin = FALSE;
+
+ SetWindowPos( mhWnd, 0,
+ maFullScreenRect.left,
+ maFullScreenRect.top,
+ maFullScreenRect.right-maFullScreenRect.left,
+ maFullScreenRect.bottom-maFullScreenRect.top,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+
+ // restore show state
+ if ( mnShowState != mnFullScreenShowState )
+ {
+ mnShowState = mnFullScreenShowState;
+ if ( bVisible )
+ {
+ mbInShow = TRUE;
+ ShowWindow( mhWnd, mnShowState );
+ mbInShow = FALSE;
+ UpdateWindow( mhWnd );
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::StartPresentation( sal_Bool bStart )
+{
+ if ( mbPresentation == bStart )
+ return;
+
+ mbPresentation = bStart;
+
+ SalData* pSalData = GetSalData();
+ if ( bStart )
+ {
+ if ( !pSalData->mpSageEnableProc )
+ {
+ if ( pSalData->mnSageStatus != DISABLE_AGENT )
+ {
+ OFSTRUCT aOS;
+ OpenFile( "SAGE.DLL", &aOS, OF_EXIST );
+
+ if ( !aOS.nErrCode )
+ {
+ OUString aLibraryName( OUString::createFromAscii( aOS.szPathName ) );
+ oslModule mhSageInst = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ pSalData->mpSageEnableProc = (SysAgt_Enable_PROC)osl_getAsciiFunctionSymbol( mhSageInst, "System_Agent_Enable" );
+ }
+ else
+ pSalData->mnSageStatus = DISABLE_AGENT;
+ }
+ }
+
+ if ( pSalData->mpSageEnableProc )
+ {
+ pSalData->mnSageStatus = pSalData->mpSageEnableProc( GET_AGENT_STATUS );
+ if ( pSalData->mnSageStatus == ENABLE_AGENT )
+ pSalData->mpSageEnableProc( DISABLE_AGENT );
+ }
+
+ // Bildschirmschoner ausschalten, wenn Praesentation laueft
+ SystemParametersInfo( SPI_GETSCREENSAVEACTIVE, 0,
+ &(pSalData->mbScrSvrEnabled), 0 );
+ if ( pSalData->mbScrSvrEnabled )
+ SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0 );
+ }
+ else
+ {
+ // Bildschirmschoner wieder einschalten
+ if ( pSalData->mbScrSvrEnabled )
+ SystemParametersInfo( SPI_SETSCREENSAVEACTIVE, pSalData->mbScrSvrEnabled, 0, 0 );
+
+ // Systemagenten wieder aktivieren
+ if ( pSalData->mnSageStatus == ENABLE_AGENT )
+ pSalData->mpSageEnableProc( pSalData->mnSageStatus );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetAlwaysOnTop( sal_Bool bOnTop )
+{
+ HWND hWnd;
+ if ( bOnTop )
+ hWnd = HWND_TOPMOST;
+ else
+ hWnd = HWND_NOTOPMOST;
+ SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalToTop( HWND hWnd, sal_uInt16 nFlags )
+{
+ WinSalFrame* pToTopFrame = GetWindowPtr( hWnd );
+ if( pToTopFrame && (pToTopFrame->mnStyle & SAL_FRAME_STYLE_SYSTEMCHILD) != 0 )
+ BringWindowToTop( hWnd );
+
+ if ( nFlags & SAL_FRAME_TOTOP_FOREGROUNDTASK )
+ {
+ // This magic code is necessary to connect the input focus of the
+ // current window thread and the thread which owns the window that
+ // should be the new foreground window.
+ HWND hCurrWnd = GetForegroundWindow();
+ DWORD myThreadID = GetCurrentThreadId();
+ DWORD currThreadID = GetWindowThreadProcessId(hCurrWnd,NULL);
+ AttachThreadInput(myThreadID, currThreadID,TRUE);
+ SetForegroundWindow(hWnd);
+ AttachThreadInput(myThreadID,currThreadID,FALSE);
+ }
+
+ if ( nFlags & SAL_FRAME_TOTOP_RESTOREWHENMIN )
+ {
+ HWND hIconicWnd = hWnd;
+ while ( hIconicWnd )
+ {
+ if ( IsIconic( hIconicWnd ) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hIconicWnd );
+ if ( pFrame )
+ {
+ if ( GetWindowPtr( hWnd )->mbRestoreMaximize )
+ ShowWindow( hIconicWnd, SW_MAXIMIZE );
+ else
+ ShowWindow( hIconicWnd, SW_RESTORE );
+ }
+ else
+ ShowWindow( hIconicWnd, SW_RESTORE );
+ }
+
+ hIconicWnd = ::GetParent( hIconicWnd );
+ }
+ }
+
+ if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) )
+ {
+ SetFocus( hWnd );
+
+ // Windows behauptet oefters mal, das man den Focus hat, obwohl
+ // man diesen nicht hat. Wenn dies der Fall ist, dann versuchen
+ // wir diesen auch ganz richtig zu bekommen.
+ if ( ::GetFocus() == hWnd )
+ SetForegroundWindow( hWnd );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ToTop( sal_uInt16 nFlags )
+{
+ nFlags &= ~SAL_FRAME_TOTOP_GRABFOCUS; // this flag is not needed on win32
+ // Post this Message to the window, because this only works
+ // in the thread of the window, which has create this window.
+ // We post this message to avoid deadlocks
+ if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
+ ImplPostMessage( mhWnd, SAL_MSG_TOTOP, nFlags, 0 );
+ else
+ ImplSalToTop( mhWnd, nFlags );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPointer( PointerStyle ePointerStyle )
+{
+ struct ImplPtrData
+ {
+ HCURSOR mhCursor;
+ LPCSTR mnSysId;
+ UINT mnOwnId;
+ };
+
+ static ImplPtrData aImplPtrTab[POINTER_COUNT] =
+ {
+ { 0, IDC_ARROW, 0 }, // POINTER_ARROW
+ { 0, 0, SAL_RESID_POINTER_NULL }, // POINTER_NULL
+ { 0, IDC_WAIT, 0 }, // POINTER_WAIT
+ { 0, IDC_IBEAM, 0 }, // POINTER_TEXT
+ { 0, IDC_HELP, 0 }, // POINTER_HELP
+ { 0, 0, SAL_RESID_POINTER_CROSS }, // POINTER_CROSS
+ { 0, 0, SAL_RESID_POINTER_MOVE }, // POINTER_MOVE
+ { 0, IDC_SIZENS, 0 }, // POINTER_NSIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_SSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_ESIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_NWSIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_NESIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_SWSIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_SESIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_NSIZE
+ { 0, IDC_SIZENS, 0 }, // POINTER_WINDOW_SSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE
+ { 0, IDC_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE
+ { 0, IDC_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE
+ { 0, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE
+ { 0, 0, SAL_RESID_POINTER_HSPLIT }, // POINTER_HSPLIT
+ { 0, 0, SAL_RESID_POINTER_VSPLIT }, // POINTER_VSPLIT
+ { 0, 0, SAL_RESID_POINTER_HSIZEBAR }, // POINTER_HSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_VSIZEBAR }, // POINTER_VSIZEBAR
+ { 0, 0, SAL_RESID_POINTER_HAND }, // POINTER_HAND
+ { 0, 0, SAL_RESID_POINTER_REFHAND }, // POINTER_REFHAND
+ { 0, 0, SAL_RESID_POINTER_PEN }, // POINTER_PEN
+ { 0, 0, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
+ { 0, 0, SAL_RESID_POINTER_FILL }, // POINTER_FILL
+ { 0, 0, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE
+ { 0, 0, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR
+ { 0, 0, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR
+ { 0, 0, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR
+ { 0, 0, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK
+ { 0, 0, SAL_RESID_POINTER_CROP }, // POINTER_CROP
+ { 0, 0, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
+ { 0, 0, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
+ { 0, 0, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
+ { 0, 0, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
+ { 0, 0, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
+ { 0, 0, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
+ { 0, 0, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
+ { 0, 0, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
+ { 0, 0, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
+ { 0, 0, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
+ { 0, 0, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
+ { 0, 0, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
+ { 0, 0, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
+ { 0, 0, SAL_RESID_POINTER_NOTALLOWED }, // POINTER_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
+ { 0, 0, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
+ { 0, 0, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
+ { 0, 0, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
+ { 0, 0, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
+ { 0, 0, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
+ { 0, 0, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
+ { 0, 0, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
+ { 0, 0, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
+ { 0, 0, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
+ { 0, 0, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
+ { 0, 0, SAL_RESID_POINTER_CHART }, // POINTER_CHART
+ { 0, 0, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
+ { 0, 0, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
+ { 0, 0, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
+ { 0, 0, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN
+ { 0, 0, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_MOVE }, // POINTER_TIMEEVENT_MOVE
+ { 0, 0, SAL_RESID_POINTER_TIMEEVENT_SIZE }, // POINTER_TIMEEVENT_SIZE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
+ { 0, 0, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
+ { 0, 0, SAL_RESID_POINTER_AIRBRUSH }, // POINTER_AIRBRUSH
+ { 0, 0, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
+ { 0, 0, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
+
+ // --> FME 2004-07-30 #i32329# Enhanced table selection
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
+ { 0, 0, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
+ // <--
+
+ // --> FME 2004-08-16 #i20119# Paintbrush tool
+ { 0, 0, SAL_RESID_POINTER_PAINTBRUSH } // POINTER_PAINTBRUSH
+ // <--
+
+ };
+
+#if POINTER_COUNT != 94
+#error New Pointer must be defined!
+#endif
+
+ // Mousepointer loaded ?
+ if ( !aImplPtrTab[ePointerStyle].mhCursor )
+ {
+ if ( aImplPtrTab[ePointerStyle].mnOwnId )
+ aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId );
+ else
+ aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( 0, aImplPtrTab[ePointerStyle].mnSysId );
+ }
+
+ // Unterscheidet sich der Mauspointer, dann den neuen setzen
+ if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor )
+ {
+ mhCursor = aImplPtrTab[ePointerStyle].mhCursor;
+ SetCursor( mhCursor );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::CaptureMouse( sal_Bool bCapture )
+{
+ // Send this Message to the window, because CaptureMouse() only work
+ // in the thread of the window, which has create this window
+ int nMsg;
+ if ( bCapture )
+ nMsg = SAL_MSG_CAPTUREMOUSE;
+ else
+ nMsg = SAL_MSG_RELEASEMOUSE;
+ ImplSendMessage( mhWnd, nMsg, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetPointerPos( long nX, long nY )
+{
+ POINT aPt;
+ aPt.x = (int)nX;
+ aPt.y = (int)nY;
+ ClientToScreen( mhWnd, &aPt );
+ SetCursorPos( aPt.x, aPt.y );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Flush()
+{
+ GdiFlush();
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Sync()
+{
+ GdiFlush();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ sal_Bool bIME = (pContext->mnOptions & SAL_INPUTCONTEXT_TEXT) != 0;
+ if ( bIME )
+ {
+ if ( !pFrame->mbIME )
+ {
+ pFrame->mbIME = TRUE;
+
+ if ( pFrame->mhDefIMEContext )
+ {
+ ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext );
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+ }
+
+ // When the application can't handle IME messages, then the
+ // System should handle the IME handling
+ if ( !(pContext->mnOptions & SAL_INPUTCONTEXT_EXTTEXTINPUT) )
+ pFrame->mbHandleIME = FALSE;
+
+ // Set the Font for IME Handling
+ if ( pContext->mpFont )
+ {
+ HIMC hIMC = ImmGetContext( pFrame->mhWnd );
+ if ( hIMC )
+ {
+ LOGFONTW aLogFont;
+ HDC hDC = GetDC( pFrame->mhWnd );
+ // In case of vertical writing, always append a '@' to the
+ // Windows font name, not only if such a Windows font really is
+ // available (bTestVerticalAvail == false in the below call):
+ // The Windows IME's candidates window seems to always use a
+ // font that has all necessary glyphs, not necessarily the one
+ // specified by this font name; but it seems to decide whether
+ // to use that font's horizontal or vertical variant based on a
+ // '@' in front of this font name.
+ ImplGetLogFontFromFontSelect( hDC, pContext->mpFont, aLogFont,
+ false );
+ ReleaseDC( pFrame->mhWnd, hDC );
+ ImmSetCompositionFontW( hIMC, &aLogFont );
+ ImmReleaseContext( pFrame->mhWnd, hIMC );
+ }
+ }
+ }
+ else
+ {
+ if ( pFrame->mbIME )
+ {
+ pFrame->mbIME = FALSE;
+ pFrame->mbHandleIME = FALSE;
+ ImmAssociateContext( pFrame->mhWnd, 0 );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetInputContext( SalInputContext* pContext )
+{
+ // Must be called in the main thread!
+ ImplSendMessage( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, (LPARAM)(void*)pContext );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalFrameEndExtTextInput( HWND hWnd, sal_uInt16 nFlags )
+{
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ DWORD nIndex;
+ if ( nFlags & SAL_FRAME_ENDEXTTEXTINPUT_COMPLETE )
+ nIndex = CPS_COMPLETE;
+ else
+ nIndex = CPS_CANCEL;
+
+ ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 );
+ ImmReleaseContext( hWnd, hIMC );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::EndExtTextInput( sal_uInt16 nFlags )
+{
+ // Must be called in the main thread!
+ ImplSendMessage( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, (WPARAM)nFlags, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf,
+ UINT& rCount, UINT nMaxSize,
+ const sal_Char* pReplace )
+{
+ DBG_ASSERT( sizeof( WCHAR ) == sizeof( xub_Unicode ), "WinSalFrame::ImplGetKeyNameTextW(): WCHAR != sal_Unicode" );
+
+ static const int nMaxKeyLen = 350;
+ WCHAR aKeyBuf[ nMaxKeyLen ];
+ int nKeyLen = 0;
+ if ( lParam )
+ {
+ if ( true/*aSalShlData.mbWNT*/ )
+ {
+ nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen );
+ // #i12401# the current unicows.dll has a bug in CharUpperBuffW, which corrupts the stack
+ // fall back to the ANSI version instead
+ DBG_ASSERT( nKeyLen <= nMaxKeyLen, "Invalid key name length!" );
+ if( nKeyLen > nMaxKeyLen )
+ nKeyLen = 0;
+ else if( nKeyLen > 0 )
+ {
+ // Capitalize just the first letter of key names
+ CharLowerBuffW( aKeyBuf, nKeyLen );
+
+ bool bUpper = true;
+ for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW )
+ {
+ if( bUpper )
+ CharUpperBuffW( pW, 1 );
+ bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.');
+ }
+ }
+ }
+ }
+
+ if ( (nKeyLen > 0) || pReplace )
+ {
+ if( (rCount > 0) && (rCount < nMaxSize) )
+ {
+ pBuf[rCount] = '+';
+ rCount++;
+ }
+
+ if( nKeyLen > 0 )
+ {
+ if( nKeyLen + rCount > nMaxSize )
+ nKeyLen = nMaxSize - rCount;
+ memcpy( pBuf+rCount, aKeyBuf, nKeyLen*sizeof( sal_Unicode ) );
+ rCount += nKeyLen;
+ }
+ else // fall back to provided default name
+ {
+ while( *pReplace && (rCount < nMaxSize) )
+ {
+ pBuf[rCount] = *pReplace;
+ rCount++;
+ pReplace++;
+ }
+ }
+ }
+ else
+ rCount = 0;
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalFrame::GetKeyName( sal_uInt16 nKeyCode )
+{
+ static const int nMaxKeyLen = 350;
+ sal_Unicode aKeyBuf[ nMaxKeyLen ];
+ UINT nKeyBufLen = 0;
+ UINT nSysCode = 0;
+
+ if ( nKeyCode & KEY_MOD1 )
+ {
+ nSysCode = MapVirtualKey( VK_CONTROL, 0 );
+ nSysCode = (nSysCode << 16) | (((sal_uLong)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" );
+ }
+
+ if ( nKeyCode & KEY_MOD2 )
+ {
+ nSysCode = MapVirtualKey( VK_MENU, 0 );
+ nSysCode = (nSysCode << 16) | (((sal_uLong)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" );
+ }
+
+ if ( nKeyCode & KEY_SHIFT )
+ {
+ nSysCode = MapVirtualKey( VK_SHIFT, 0 );
+ nSysCode = (nSysCode << 16) | (((sal_uLong)1) << 25);
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" );
+ }
+
+ sal_uInt16 nCode = nKeyCode & 0x0FFF;
+ sal_uLong nSysCode2 = 0;
+ sal_Char* pReplace = NULL;
+ sal_Unicode cSVCode = 0;
+ sal_Char aFBuf[4];
+ nSysCode = 0;
+
+ if ( (nCode >= KEY_0) && (nCode <= KEY_9) )
+ cSVCode = '0' + (nCode - KEY_0);
+ else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) )
+ cSVCode = 'A' + (nCode - KEY_A);
+ else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) )
+ {
+ nSysCode = VK_F1 + (nCode - KEY_F1);
+ aFBuf[0] = 'F';
+ if ( (nCode >= KEY_F1) && (nCode <= KEY_F9) )
+ {
+ aFBuf[1] = sal::static_int_cast<sal_Char>('1' + (nCode - KEY_F1));
+ aFBuf[2] = 0;
+ }
+ else if ( (nCode >= KEY_F10) && (nCode <= KEY_F19) )
+ {
+ aFBuf[1] = '1';
+ aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F10));
+ aFBuf[3] = 0;
+ }
+ else
+ {
+ aFBuf[1] = '2';
+ aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F20));
+ aFBuf[3] = 0;
+ }
+ pReplace = aFBuf;
+ }
+ else
+ {
+ switch ( nCode )
+ {
+ case KEY_DOWN:
+ nSysCode = VK_DOWN;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Down";
+ break;
+ case KEY_UP:
+ nSysCode = VK_UP;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Up";
+ break;
+ case KEY_LEFT:
+ nSysCode = VK_LEFT;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Left";
+ break;
+ case KEY_RIGHT:
+ nSysCode = VK_RIGHT;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Right";
+ break;
+ case KEY_HOME:
+ nSysCode = VK_HOME;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Home";
+ break;
+ case KEY_END:
+ nSysCode = VK_END;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "End";
+ break;
+ case KEY_PAGEUP:
+ nSysCode = VK_PRIOR;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Page Up";
+ break;
+ case KEY_PAGEDOWN:
+ nSysCode = VK_NEXT;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Page Down";
+ break;
+ case KEY_RETURN:
+ nSysCode = VK_RETURN;
+ pReplace = "Enter";
+ break;
+ case KEY_ESCAPE:
+ nSysCode = VK_ESCAPE;
+ pReplace = "Escape";
+ break;
+ case KEY_TAB:
+ nSysCode = VK_TAB;
+ pReplace = "Tab";
+ break;
+ case KEY_BACKSPACE:
+ nSysCode = VK_BACK;
+ pReplace = "Backspace";
+ break;
+ case KEY_SPACE:
+ nSysCode = VK_SPACE;
+ pReplace = "Space";
+ break;
+ case KEY_INSERT:
+ nSysCode = VK_INSERT;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Insert";
+ break;
+ case KEY_DELETE:
+ nSysCode = VK_DELETE;
+ nSysCode2 = (((sal_uLong)1) << 24);
+ pReplace = "Delete";
+ break;
+
+ case KEY_ADD:
+ cSVCode = '+';
+ break;
+ case KEY_SUBTRACT:
+ cSVCode = '-';
+ break;
+ case KEY_MULTIPLY:
+ cSVCode = '*';
+ break;
+ case KEY_DIVIDE:
+ cSVCode = '/';
+ break;
+ case KEY_POINT:
+ cSVCode = '.';
+ break;
+ case KEY_COMMA:
+ cSVCode = ',';
+ break;
+ case KEY_LESS:
+ cSVCode = '<';
+ break;
+ case KEY_GREATER:
+ cSVCode = '>';
+ break;
+ case KEY_EQUAL:
+ cSVCode = '=';
+ break;
+ }
+ }
+
+ if ( nSysCode )
+ {
+ nSysCode = MapVirtualKey( (UINT)nSysCode, 0 );
+ if ( nSysCode )
+ nSysCode = (nSysCode << 16) | nSysCode2;
+ ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace );
+ }
+ else
+ {
+ if ( cSVCode )
+ {
+ if ( nKeyBufLen > 0 )
+ aKeyBuf[ nKeyBufLen++ ] = '+';
+ if( nKeyBufLen < nMaxKeyLen )
+ aKeyBuf[ nKeyBufLen++ ] = cSVCode;
+ }
+ }
+
+ if( !nKeyBufLen )
+ return XubString();
+
+ return XubString( aKeyBuf, sal::static_int_cast< sal_uInt16 >(nKeyBufLen) );
+}
+
+// -----------------------------------------------------------------------
+
+XubString WinSalFrame::GetSymbolKeyName( const XubString&, sal_uInt16 nKeyCode )
+{
+ return GetKeyName( nKeyCode );
+}
+
+// -----------------------------------------------------------------------
+
+inline Color ImplWinColorToSal( COLORREF nColor )
+{
+ return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalUpdateStyleFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
+{
+ ImplSalLogFontToFontA( hDC, rLogFont, rFont );
+
+ // On Windows 9x, Windows NT we get sometimes very small sizes
+ // (for example for the small Caption height).
+ // So if it is MS Sans Serif, a none scalable font we use
+ // 8 Point as the minimum control height, in all other cases
+ // 6 Point is the smallest one
+ if ( rFont.GetHeight() < 8 )
+ {
+ if ( rtl_str_compareIgnoreAsciiCase( rLogFont.lfFaceName, "MS Sans Serif" ) == 0 )
+ rFont.SetHeight( 8 );
+ else if ( rFont.GetHeight() < 6 )
+ rFont.SetHeight( 6 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
+{
+ ImplSalLogFontToFontW( hDC, rLogFont, rFont );
+
+ // On Windows 9x, Windows NT we get sometimes very small sizes
+ // (for example for the small Caption height).
+ // So if it is MS Sans Serif, a none scalable font we use
+ // 8 Point as the minimum control height, in all other cases
+ // 6 Point is the smallest one
+ if ( rFont.GetHeight() < 8 )
+ {
+ if ( rtl_ustr_compareIgnoreAsciiCase( reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName), reinterpret_cast<const sal_Unicode*>(L"MS Sans Serif") ) == 0 )
+ rFont.SetHeight( 8 );
+ else if ( rFont.GetHeight() < 6 )
+ rFont.SetHeight( 6 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplA2I( const BYTE* pStr )
+{
+ long n = 0;
+ int nSign = 1;
+
+ if ( *pStr == '-' )
+ {
+ nSign = -1;
+ pStr++;
+ }
+
+ while( (*pStr >= 48) && (*pStr <= 57) )
+ {
+ n *= 10;
+ n += ((*pStr) - 48);
+ pStr++;
+ }
+
+ n *= nSign;
+
+ return n;
+}
+
+// -----------------------------------------------------------------------
+static HRESULT WINAPI backwardCompatibleDwmIsCompositionEnabled( BOOL* pOut )
+{
+ *pOut = FALSE;
+ return S_OK;
+}
+
+static BOOL ImplDwmIsCompositionEnabled()
+{
+ SalData* pSalData = GetSalData();
+ if( ! pSalData->mpDwmIsCompositionEnabled )
+ {
+ rtl::OUString aLibraryName( RTL_CONSTASCII_USTRINGPARAM( "Dwmapi.dll" ) );
+ pSalData->maDwmLib = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
+ if( pSalData->maDwmLib )
+ pSalData->mpDwmIsCompositionEnabled = (DwmIsCompositionEnabled_ptr)osl_getAsciiFunctionSymbol( pSalData->maDwmLib, "DwmIsCompositionEnabled" );
+ if( ! pSalData->mpDwmIsCompositionEnabled ) // something failed
+ pSalData->mpDwmIsCompositionEnabled = backwardCompatibleDwmIsCompositionEnabled;
+ }
+ BOOL aResult = FALSE;
+ HRESULT nError = pSalData->mpDwmIsCompositionEnabled( &aResult );
+ return nError == S_OK && aResult;
+}
+
+
+void WinSalFrame::UpdateSettings( AllSettings& rSettings )
+{
+ MouseSettings aMouseSettings = rSettings.GetMouseSettings();
+ aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() );
+ aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) );
+ aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) );
+ long nDragWidth = GetSystemMetrics( SM_CXDRAG );
+ long nDragHeight = GetSystemMetrics( SM_CYDRAG );
+ if ( nDragWidth )
+ aMouseSettings.SetStartDragWidth( nDragWidth );
+ if ( nDragHeight )
+ aMouseSettings.SetStartDragHeight( nDragHeight );
+ HKEY hRegKey;
+ if ( RegOpenKey( HKEY_CURRENT_USER,
+ "Control Panel\\Desktop",
+ &hRegKey ) == ERROR_SUCCESS )
+ {
+ BYTE aValueBuf[10];
+ DWORD nValueSize = sizeof( aValueBuf );
+ DWORD nType;
+ if ( RegQueryValueEx( hRegKey, "MenuShowDelay", 0,
+ &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS )
+ {
+ if ( nType == REG_SZ )
+ aMouseSettings.SetMenuDelay( (sal_uLong)ImplA2I( aValueBuf ) );
+ }
+
+ RegCloseKey( hRegKey );
+ }
+
+ StyleSettings aStyleSettings = rSettings.GetStyleSettings();
+ // TODO: once those options vanish: just set bCompBorder to TRUE
+ // to have the system colors read
+ aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) );
+ aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) );
+ aStyleSettings.SetCursorBlinkTime( GetCaretBlinkTime() );
+ aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) );
+ aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) );
+ aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
+ aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
+ if ( aSalShlData.mnVersion >= 410 )
+ {
+ aStyleSettings.SetActiveColor2( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTACTIVECAPTION ) ) );
+ aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
+ }
+ aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
+ aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
+ aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
+ aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
+ aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
+ aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) );
+ aStyleSettings.SetWorkspaceColor( ImplWinColorToSal( GetSysColor( COLOR_APPWORKSPACE ) ) );
+ aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
+ aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
+ aStyleSettings.SetDialogColor( aStyleSettings.GetFaceColor() );
+ aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetButtonTextColor( ImplWinColorToSal( GetSysColor( COLOR_BTNTEXT ) ) );
+ aStyleSettings.SetButtonRolloverTextColor( aStyleSettings.GetButtonTextColor() );
+ aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetInfoTextColor( aStyleSettings.GetRadioCheckTextColor() );
+ aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
+ aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
+ aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
+ aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
+ aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
+ aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() );
+ aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
+ aStyleSettings.SetHighlightTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) );
+ aStyleSettings.SetMenuHighlightColor( aStyleSettings.GetHighlightColor() );
+ aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
+
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maNWFData.mnMenuFormatExtraBorder = 0;
+ pSVData->maNWFData.maMenuBarHighlightTextColor = Color( COL_TRANSPARENT );
+ GetSalData()->mbThemeMenuSupport = FALSE;
+ aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
+ aStyleSettings.SetMenuBarColor( aStyleSettings.GetMenuColor() );
+ aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overriden below for flat menus
+ aStyleSettings.SetUseFlatBorders( FALSE );
+ aStyleSettings.SetUseFlatMenues( FALSE );
+ aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
+ aStyleSettings.SetMenuBarTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
+ aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
+ aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
+ aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) );
+ aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) );
+ if ( aSalShlData.mbWXP )
+ {
+ // only xp supports a different menu bar color
+ long bFlatMenues = 0;
+ SystemParametersInfo( SPI_GETFLATMENU, 0, &bFlatMenues, 0);
+ if( bFlatMenues )
+ {
+ aStyleSettings.SetUseFlatMenues( TRUE );
+ aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) );
+ aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
+ aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
+
+ // flat borders for our controls etc. as well in this mode (ie, no 3d borders)
+ // this is not active in the classic style appearance
+ aStyleSettings.SetUseFlatBorders( TRUE );
+ }
+ }
+ // check if vista or newer runs
+ // in Aero theme (and similar ?) the menu text color does not change
+ // for selected items; also on WinXP and earlier menus are not themed
+ if( aSalShlData.maVersionInfo.dwMajorVersion >= 6 &&
+ ImplDwmIsCompositionEnabled()
+ )
+ {
+ // in aero menuitem highlight text is drawn in the same color as normal
+ aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetMenuTextColor() );
+ pSVData->maNWFData.mnMenuFormatExtraBorder = 2;
+ pSVData->maNWFData.maMenuBarHighlightTextColor = aStyleSettings.GetMenuTextColor();
+ GetSalData()->mbThemeMenuSupport = TRUE;
+ }
+ // Bei hellgrau geben wir die Farbe vor, damit es besser aussieht
+ if ( aStyleSettings.GetFaceColor() == COL_LIGHTGRAY )
+ aStyleSettings.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
+ else
+ {
+ // Checked-Color berechnen
+ Color aColor1 = aStyleSettings.GetFaceColor();
+ Color aColor2 = aStyleSettings.GetLightColor();
+ BYTE nRed = (BYTE)(((sal_uInt16)aColor1.GetRed() + (sal_uInt16)aColor2.GetRed())/2);
+ BYTE nGreen = (BYTE)(((sal_uInt16)aColor1.GetGreen() + (sal_uInt16)aColor2.GetGreen())/2);
+ BYTE nBlue = (BYTE)(((sal_uInt16)aColor1.GetBlue() + (sal_uInt16)aColor2.GetBlue())/2);
+ aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) );
+ }
+
+ // caret width
+ DWORD nCaretWidth = 2;
+ if( SystemParametersInfo( SPI_GETCARETWIDTH, 0, &nCaretWidth, 0 ) )
+ aStyleSettings.SetCursorSize( nCaretWidth );
+
+ // High contrast
+ HIGHCONTRAST hc;
+ hc.cbSize = sizeof( HIGHCONTRAST );
+ if( SystemParametersInfo( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0) && (hc.dwFlags & HCF_HIGHCONTRASTON) )
+ aStyleSettings.SetHighContrastMode( 1 );
+ else
+ aStyleSettings.SetHighContrastMode( 0 );
+
+
+ // Query Fonts
+ Font aMenuFont = aStyleSettings.GetMenuFont();
+ Font aTitleFont = aStyleSettings.GetTitleFont();
+ Font aFloatTitleFont = aStyleSettings.GetFloatTitleFont();
+ Font aHelpFont = aStyleSettings.GetHelpFont();
+ Font aAppFont = aStyleSettings.GetAppFont();
+ Font aIconFont = aStyleSettings.GetIconFont();
+ HDC hDC = GetDC( 0 );
+ if( true/*aSalShlData.mbWNT*/ )
+ {
+ NONCLIENTMETRICSW aNonClientMetrics;
+ aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
+ if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
+ {
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
+ ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
+
+ LOGFONTW aLogFont;
+ if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
+ ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont );
+ }
+ }
+
+ // get screen font resolution to calculate toolbox item size
+ long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
+
+ ReleaseDC( 0, hDC );
+
+ long nHeightPx = aMenuFont.GetHeight() * nDPIY / 72;
+ aStyleSettings.SetToolbarIconSize( (((nHeightPx-1)*2) >= 28) ? STYLE_TOOLBAR_ICONSIZE_LARGE : STYLE_TOOLBAR_ICONSIZE_SMALL );
+
+ aStyleSettings.SetMenuFont( aMenuFont );
+ aStyleSettings.SetTitleFont( aTitleFont );
+ aStyleSettings.SetFloatTitleFont( aFloatTitleFont );
+ aStyleSettings.SetHelpFont( aHelpFont );
+ aStyleSettings.SetIconFont( aIconFont );
+ // We prefer Arial in the russian version, because MS Sans Serif
+ // is to wide for the dialogs
+ if ( rSettings.GetLanguage() == LANGUAGE_RUSSIAN )
+ {
+ XubString aFontName = aAppFont.GetName();
+ XubString aFirstName = aFontName.GetToken( 0, ';' );
+ if ( aFirstName.EqualsIgnoreCaseAscii( "MS Sans Serif" ) )
+ {
+ aFontName.InsertAscii( "Arial;", 0 );
+ aAppFont.SetName( aFontName );
+ }
+ }
+ aStyleSettings.SetAppFont( aAppFont );
+ aStyleSettings.SetGroupFont( aAppFont );
+ aStyleSettings.SetLabelFont( aAppFont );
+ aStyleSettings.SetRadioCheckFont( aAppFont );
+ aStyleSettings.SetPushButtonFont( aAppFont );
+ aStyleSettings.SetFieldFont( aAppFont );
+ if ( aAppFont.GetWeight() > WEIGHT_NORMAL )
+ aAppFont.SetWeight( WEIGHT_NORMAL );
+ aStyleSettings.SetInfoFont( aAppFont );
+ aStyleSettings.SetToolFont( aAppFont );
+
+ BOOL bDragFull;
+ if ( SystemParametersInfo( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) )
+ {
+ sal_uLong nDragFullOptions = aStyleSettings.GetDragFullOptions();
+ if ( bDragFull )
+ nDragFullOptions |= DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT;
+ else
+ nDragFullOptions &= ~(DRAGFULL_OPTION_WINDOWMOVE | DRAGFULL_OPTION_WINDOWSIZE | DRAGFULL_OPTION_DOCKING | DRAGFULL_OPTION_SPLIT);
+ aStyleSettings.SetDragFullOptions( nDragFullOptions );
+ }
+
+ aStyleSettings.SetIconHorzSpace( GetSystemMetrics( SM_CXICONSPACING ) );
+ aStyleSettings.SetIconVertSpace( GetSystemMetrics( SM_CYICONSPACING ) );
+ if ( RegOpenKey( HKEY_CURRENT_USER,
+ "Control Panel\\International\\Calendars\\TwoDigitYearMax",
+ &hRegKey ) == ERROR_SUCCESS )
+ {
+ BYTE aValueBuf[10];
+ DWORD nValue;
+ DWORD nValueSize = sizeof( aValueBuf );
+ DWORD nType;
+ if ( RegQueryValueEx( hRegKey, "1", 0,
+ &nType, aValueBuf, &nValueSize ) == ERROR_SUCCESS )
+ {
+ if ( nType == REG_SZ )
+ {
+ nValue = (sal_uLong)ImplA2I( aValueBuf );
+ if ( (nValue > 1000) && (nValue < 10000) )
+ {
+ MiscSettings aMiscSettings = rSettings.GetMiscSettings();
+ utl::MiscCfg().SetYear2000( (sal_Int32)(nValue-99) );
+ rSettings.SetMiscSettings( aMiscSettings );
+ }
+ }
+ }
+
+ RegCloseKey( hRegKey );
+ }
+
+ rSettings.SetMouseSettings( aMouseSettings );
+ rSettings.SetStyleSettings( aStyleSettings );
+}
+
+// -----------------------------------------------------------------------
+
+SalBitmap* WinSalFrame::SnapShot()
+{
+ WinSalBitmap* pSalBitmap = NULL;
+
+ RECT aRect;
+ GetWindowRect( mhWnd, &aRect );
+
+ int nDX = aRect.right-aRect.left;
+ int nDY = aRect.bottom-aRect.top;
+ HDC hDC = GetWindowDC( mhWnd );
+ HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
+ HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
+ sal_Bool bRet;
+
+ bRet = BitBlt( hBmpDC, 0, 0, nDX, nDY, hDC, 0, 0, SRCCOPY ) ? TRUE : FALSE;
+ ImplReleaseCachedDC( CACHED_HDC_1 );
+
+ if ( bRet )
+ {
+ pSalBitmap = new WinSalBitmap;
+
+ if ( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
+ {
+ delete pSalBitmap;
+ pSalBitmap = NULL;
+ }
+ }
+
+ return pSalBitmap;
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* WinSalFrame::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::Beep( SoundType eSoundType )
+{
+ static UINT aImplSoundTab[5] =
+ {
+ 0, // SOUND_DEFAULT
+ MB_ICONASTERISK, // SOUND_INFO
+ MB_ICONEXCLAMATION, // SOUND_WARNING
+ MB_ICONHAND, // SOUND_ERROR
+ MB_ICONQUESTION // SOUND_QUERY
+ };
+
+ if( eSoundType != SOUND_DISABLE ) // don't beep on disable
+ MessageBeep( aImplSoundTab[eSoundType] );
+}
+
+// -----------------------------------------------------------------------
+
+SalFrame::SalPointerState WinSalFrame::GetPointerState()
+{
+ SalPointerState aState;
+ aState.mnState = 0;
+
+ if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_LEFT;
+ if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_MIDDLE;
+ if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
+ aState.mnState |= MOUSE_RIGHT;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ aState.mnState |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ aState.mnState |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aState.mnState |= KEY_MOD2;
+
+ POINT pt;
+ GetCursorPos( &pt );
+
+ aState.maPos = Point( pt.x - maGeometry.nX, pt.y - maGeometry.nY );
+ return aState;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::SetBackgroundBitmap( SalBitmap* )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::ResetClipRegion()
+{
+ SetWindowRgn( mhWnd, 0, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::BeginSetClipRegion( sal_uLong nRects )
+{
+ if( mpClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+ sal_uLong nRectBufSize = sizeof(RECT)*nRects;
+ mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
+ mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
+ mpClipRgnData->rdh.iType = RDH_RECTANGLES;
+ mpClipRgnData->rdh.nCount = nRects;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
+ mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ mbFirstClipRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ if( ! mpClipRgnData )
+ return;
+
+ RECT* pRect = mpNextClipRect;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ long nRight = nX + nWidth;
+ long nBottom = nY + nHeight;
+
+ if ( mbFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ mbFirstClipRect = FALSE;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pRect->left = (int)nX;
+ pRect->top = (int)nY;
+ pRect->right = (int)nRight;
+ pRect->bottom = (int)nBottom;
+ if( (mpNextClipRect - (RECT*)(&mpClipRgnData->Buffer)) < (int)mpClipRgnData->rdh.nCount )
+ mpNextClipRect++;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalFrame::EndSetClipRegion()
+{
+ if( ! mpClipRgnData )
+ return;
+
+ HRGN hRegion;
+
+ // create region from accumulated rectangles
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ hRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else
+ {
+ sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
+ hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
+ }
+ delete [] (BYTE*)mpClipRgnData;
+ mpClipRgnData = NULL;
+
+ DBG_ASSERT( hRegion, "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" );
+ if( hRegion )
+ {
+ RECT aWindowRect;
+ GetWindowRect( mhWnd, &aWindowRect );
+ POINT aPt;
+ aPt.x=0;
+ aPt.y=0;
+ ClientToScreen( mhWnd, &aPt );
+ OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top );
+
+ if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 )
+ DeleteObject( hRegion );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN )
+ {
+ // #103168# post again if async focus has not arrived yet
+ // hopefully we will not receive the corresponding button up before this
+ // button down arrives again
+ Window *pWin = pFrame->GetWindow();
+ if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId )
+ {
+ ImplPostMessage( hWnd, nMsg, wParam, lParam );
+ return 1;
+ }
+ }
+ SalMouseEvent aMouseEvt;
+ long nRet;
+ sal_uInt16 nEvent = 0;
+ sal_Bool bCall = TRUE;
+
+ aMouseEvt.mnX = (short)LOWORD( lParam );
+ aMouseEvt.mnY = (short)HIWORD( lParam );
+ aMouseEvt.mnCode = 0;
+ aMouseEvt.mnTime = GetMessageTime();
+
+ // Wegen (Logitech-)MouseTreiber ueber GetKeyState() gehen, die auf
+ // mittlerer Maustaste Doppelklick simulieren und den KeyStatus nicht
+ // beruecksichtigen
+
+ if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_LEFT;
+ if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_MIDDLE;
+ if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
+ aMouseEvt.mnCode |= MOUSE_RIGHT;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aMouseEvt.mnCode |= KEY_MOD2;
+
+ switch ( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ {
+ // Da bei Druecken von Modifier-Tasten die MouseEvents
+ // nicht zusammengefast werden (da diese durch KeyEvents
+ // unterbrochen werden), machen wir dieses hier selber
+ if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
+ {
+ MSG aTempMsg;
+ if ( ImplPeekMessage( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) )
+ {
+ if ( (aTempMsg.message == WM_MOUSEMOVE) &&
+ (aTempMsg.wParam == wParam) )
+ return 1;
+ }
+ }
+
+ SalData* pSalData = GetSalData();
+ // Test for MouseLeave
+ if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) )
+ ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() );
+
+ pSalData->mhWantLeaveMsg = hWnd;
+ // Start MouseLeave-Timer
+ if ( !pSalData->mpMouseLeaveTimer )
+ {
+ pSalData->mpMouseLeaveTimer = new AutoTimer;
+ pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT );
+ pSalData->mpMouseLeaveTimer->Start();
+ // We dont need to set a timeout handler, because we test
+ // for mouseleave in the timeout callback
+ }
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSEMOVE;
+ }
+ break;
+
+ case WM_NCMOUSEMOVE:
+ case SAL_MSG_MOUSELEAVE:
+ {
+ SalData* pSalData = GetSalData();
+ if ( pSalData->mhWantLeaveMsg == hWnd )
+ {
+ pSalData->mhWantLeaveMsg = 0;
+ if ( pSalData->mpMouseLeaveTimer )
+ {
+ delete pSalData->mpMouseLeaveTimer;
+ pSalData->mpMouseLeaveTimer = NULL;
+ }
+ // Mouse-Coordinaates are relativ to the screen
+ POINT aPt;
+ aPt.x = (short)LOWORD( lParam );
+ aPt.y = (short)HIWORD( lParam );
+ ScreenToClient( hWnd, &aPt );
+ aMouseEvt.mnX = aPt.x;
+ aMouseEvt.mnY = aPt.y;
+ aMouseEvt.mnButton = 0;
+ nEvent = SALEVENT_MOUSELEAVE;
+ }
+ else
+ bCall = FALSE;
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_MBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_RBUTTONDOWN:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONDOWN;
+ break;
+
+ case WM_LBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_LEFT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_MBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_MIDDLE;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+
+ case WM_RBUTTONUP:
+ aMouseEvt.mnButton = MOUSE_RIGHT;
+ nEvent = SALEVENT_MOUSEBUTTONUP;
+ break;
+ }
+
+ // check if this window was destroyed - this might happen if we are the help window
+ // and sent a mouse leave message to the application which killed the help window, ie ourself
+ if( !IsWindow( hWnd ) )
+ return 0;
+
+ if ( bCall )
+ {
+ if ( nEvent == SALEVENT_MOUSEBUTTONDOWN )
+ UpdateWindow( hWnd );
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aMouseEvt.mnX = pFrame->maGeometry.nWidth-1-aMouseEvt.mnX;
+
+ nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
+ if ( nMsg == WM_MOUSEMOVE )
+ SetCursor( pFrame->mhCursor );
+ }
+ else
+ nRet = 0;
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleMouseActivateMsg( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ if ( pFrame->mbFloatWin )
+ return TRUE;
+
+ SalMouseActivateEvent aMouseActivateEvt;
+ POINT aPt;
+ GetCursorPos( &aPt );
+ ScreenToClient( hWnd, &aPt );
+ aMouseActivateEvt.mnX = aPt.x;
+ aMouseActivateEvt.mnY = aPt.y;
+ return pFrame->CallCallback( SALEVENT_MOUSEACTIVATE, &aMouseActivateEvt );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ DBG_ASSERT( nMsg == WM_MOUSEWHEEL ||
+ nMsg == WM_MOUSEHWHEEL,
+ "ImplHandleWheelMsg() called with no wheel mouse event" );
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ long nRet = 0;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ WORD nWinModCode = LOWORD( wParam );
+ POINT aWinPt;
+ aWinPt.x = (short)LOWORD( lParam );
+ aWinPt.y = (short)HIWORD( lParam );
+ ScreenToClient( hWnd, &aWinPt );
+
+ SalWheelMouseEvent aWheelEvt;
+ aWheelEvt.mnTime = GetMessageTime();
+ aWheelEvt.mnX = aWinPt.x;
+ aWheelEvt.mnY = aWinPt.y;
+ aWheelEvt.mnCode = 0;
+ aWheelEvt.mnDelta = (short)HIWORD( wParam );
+ aWheelEvt.mnNotchDelta = aWheelEvt.mnDelta/WHEEL_DELTA;
+ if( aWheelEvt.mnNotchDelta == 0 )
+ {
+ if( aWheelEvt.mnDelta > 0 )
+ aWheelEvt.mnNotchDelta = 1;
+ else if( aWheelEvt.mnDelta < 0 )
+ aWheelEvt.mnNotchDelta = -1;
+ }
+
+ if( nMsg == WM_MOUSEWHEEL )
+ {
+ if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL )
+ aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
+ else
+ aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines;
+ aWheelEvt.mbHorz = FALSE;
+ }
+ else
+ {
+ aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars;
+ aWheelEvt.mbHorz = TRUE;
+ }
+
+ if ( nWinModCode & MK_SHIFT )
+ aWheelEvt.mnCode |= KEY_SHIFT;
+ if ( nWinModCode & MK_CONTROL )
+ aWheelEvt.mnCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ aWheelEvt.mnCode |= KEY_MOD2;
+
+ // --- RTL --- (mirror mouse pos)
+ if( Application::GetSettings().GetLayoutRTL() )
+ aWheelEvt.mnX = pFrame->maGeometry.nWidth-1-aWheelEvt.mnX;
+
+ nRet = pFrame->CallCallback( SALEVENT_WHEELMOUSE, &aWheelEvt );
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_uInt16 ImplSalGetKeyCode( WPARAM wParam )
+{
+ sal_uInt16 nKeyCode;
+
+ // convert KeyCode
+ if ( wParam < KEY_TAB_SIZE )
+ nKeyCode = aImplTranslateKeyTab[wParam];
+ else
+ {
+ SalData* pSalData = GetSalData();
+ std::map< UINT, sal_uInt16 >::const_iterator it = pSalData->maVKMap.find( (UINT)wParam );
+ if( it != pSalData->maVKMap.end() )
+ nKeyCode = it->second;
+ else
+ nKeyCode = 0;
+ }
+
+ return nKeyCode;
+}
+
+// -----------------------------------------------------------------------
+
+static UINT ImplStrToNum( const sal_Char* pStr )
+{
+ sal_uInt16 n = 0;
+
+ // Solange es sich um eine Ziffer handelt, String umwandeln
+ while( (*pStr >= 48) && (*pStr <= 57) )
+ {
+ n *= 10;
+ n += ((*pStr) - 48);
+ pStr++;
+ }
+
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateInputLang( WinSalFrame* pFrame )
+{
+ sal_Bool bLanguageChange = FALSE;
+ UINT nLang = LOWORD( GetKeyboardLayout( 0 ) );
+ if ( nLang && nLang != pFrame->mnInputLang )
+ {
+ // keep input lang up-to-date
+ pFrame->mnInputLang = nLang;
+ bLanguageChange = TRUE;
+ }
+
+ // If we are on Windows NT we use Unicode FrameProcs and so we
+ // get Unicode charcodes directly from Windows
+ // no need to set up a code page
+ return;
+}
+
+
+static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode )
+{
+ ImplUpdateInputLang( pFrame );
+
+ // If we are on Windows NT we use Unicode FrameProcs and so we
+ // get Unicode charcodes directly from Windows
+ return (sal_Unicode)nCharCode;
+}
+
+// -----------------------------------------------------------------------
+
+LanguageType WinSalFrame::GetInputLanguage()
+{
+ if( !mnInputLang )
+ ImplUpdateInputLang( this );
+
+ if( !mnInputLang )
+ return LANGUAGE_DONTKNOW;
+ else
+ return (LanguageType) mnInputLang;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode )
+{
+ sal_Bool bRet = FALSE;
+ HKL hkl = 0;
+
+ // just use the passed language identifier, do not try to load additional keyboard support
+ hkl = (HKL) aLangType;
+
+ if( hkl )
+ {
+ SHORT scan = VkKeyScanExW( aUnicode, hkl );
+ if( LOWORD(scan) == 0xFFFF )
+ // keyboard not loaded or key cannot be mapped
+ bRet = FALSE;
+ else
+ {
+ BYTE vkeycode = LOBYTE(scan);
+ BYTE shiftstate = HIBYTE(scan);
+
+ // Last argument is set to FALSE, because there's no decission made
+ // yet which key should be assigned to MOD3 modifier on Windows.
+ // Windows key - user's can be confused, because it should display
+ // Windows menu (applies to both left/right key)
+ // Menu key - this key is used to display context menu
+ // AltGr key - probably it has no sense
+ rKeyCode = KeyCode( ImplSalGetKeyCode( vkeycode ),
+ (shiftstate & 0x01) ? TRUE : FALSE, // shift
+ (shiftstate & 0x02) ? TRUE : FALSE, // ctrl
+ (shiftstate & 0x04) ? TRUE : FALSE, // alt
+ FALSE );
+ bRet = TRUE;
+ }
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam, LRESULT& rResult )
+{
+ static sal_Bool bIgnoreCharMsg = FALSE;
+ static WPARAM nDeadChar = 0;
+ static WPARAM nLastVKChar = 0;
+ static sal_uInt16 nLastChar = 0;
+ static sal_uInt16 nLastModKeyCode = 0;
+ static bool bWaitForModKeyRelease = false;
+ sal_uInt16 nRepeat = LOWORD( lParam )-1;
+ sal_uInt16 nModCode = 0;
+
+ // Key wurde evtl. durch SysChild an uns weitergeleitet und
+ // darf somit dann nicht doppelt verarbeitet werden
+ GetSalData()->mnSalObjWantKeyEvt = 0;
+
+ if ( nMsg == WM_DEADCHAR )
+ {
+ nDeadChar = wParam;
+ return 0;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ // Wir restaurieren den Background-Modus bei jeder Texteingabe,
+ // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen
+ if ( pFrame->mpGraphics &&
+ pFrame->mpGraphics->mhDC )
+ SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT );
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ nModCode |= KEY_MOD2;
+
+ if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) )
+ {
+ nDeadChar = 0;
+
+ if ( bIgnoreCharMsg )
+ {
+ bIgnoreCharMsg = FALSE;
+ // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep
+ // becaus this 'hotkey' was not processed -> better return 1
+ // except for Alt-SPACE which should always open the sysmenu (#104616#)
+
+ // also return zero if a system menubar is available that might process this hotkey
+ // this also applies to the OLE inplace embedding where we are a child window
+ if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) )
+ return 0;
+ else
+ return 1;
+ }
+
+ // Backspace ignorieren wir als eigenstaendige Taste,
+ // damit wir keine Probleme in Kombination mit einem
+ // DeadKey bekommen
+ if ( wParam == 0x08 ) // BACKSPACE
+ return 0;
+
+ // Hier kommen nur "freifliegende" WM_CHAR Message an, die durch
+ // eintippen einer ALT-NUMPAD Kombination erzeugt wurden
+ SalKeyEvent aKeyEvt;
+
+ if ( (wParam >= '0') && (wParam <= '9') )
+ aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_NUM + wParam - '0');
+ else if ( (wParam >= 'A') && (wParam <= 'Z') )
+ aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'A');
+ else if ( (wParam >= 'a') && (wParam <= 'z') )
+ aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'a');
+ else if ( wParam == 0x0D ) // RETURN
+ aKeyEvt.mnCode = KEY_RETURN;
+ else if ( wParam == 0x1B ) // ESCAPE
+ aKeyEvt.mnCode = KEY_ESCAPE;
+ else if ( wParam == 0x09 ) // TAB
+ aKeyEvt.mnCode = KEY_TAB;
+ else if ( wParam == 0x20 ) // SPACE
+ aKeyEvt.mnCode = KEY_SPACE;
+ else
+ aKeyEvt.mnCode = 0;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, wParam );
+ aKeyEvt.mnRepeat = nRepeat;
+ nLastChar = 0;
+ nLastVKChar = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return nRet;
+ }
+ // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins
+ else if( nMsg == WM_UNICHAR )
+ {
+ // If Windows is asking if we accept WM_UNICHAR, return TRUE
+ if(wParam == UNICODE_NOCHAR)
+ {
+ rResult = TRUE; // ssa: this will actually return TRUE to windows
+ return 1; // ...but this will only avoid calling the defwindowproc
+ }
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnCode = nModCode; // Or should it be 0? - as this is always a character returned
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnRepeat = 0;
+
+ if( wParam >= Uni_SupplementaryPlanesStart )
+ {
+ // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair
+ // sal_Unicode ch = (sal_Unicode) Uni_UTF32ToSurrogate1(wParam);
+ nLastChar = 0;
+ nLastVKChar = 0;
+ pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ wParam = (sal_Unicode) Uni_UTF32ToSurrogate2( wParam );
+ }
+
+ aKeyEvt.mnCharCode = (sal_Unicode) wParam;
+
+ nLastChar = 0;
+ nLastVKChar = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+
+ return nRet;
+ }
+ // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
+ else
+ {
+ // Bei Shift, Control und Menu schicken wir einen KeyModChange-Event
+ if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) )
+ {
+ SalKeyModEvent aModEvt;
+ aModEvt.mnTime = GetMessageTime();
+ aModEvt.mnCode = nModCode;
+ aModEvt.mnModKeyCode = 0; // no command events will be sent if this member is 0
+
+ sal_uInt16 tmpCode = 0;
+ if( GetKeyState( VK_LSHIFT ) & 0x8000 )
+ tmpCode |= MODKEY_LSHIFT;
+ if( GetKeyState( VK_RSHIFT ) & 0x8000 )
+ tmpCode |= MODKEY_RSHIFT;
+ if( GetKeyState( VK_LCONTROL ) & 0x8000 )
+ tmpCode |= MODKEY_LMOD1;
+ if( GetKeyState( VK_RCONTROL ) & 0x8000 )
+ tmpCode |= MODKEY_RMOD1;
+ if( GetKeyState( VK_LMENU ) & 0x8000 )
+ tmpCode |= MODKEY_LMOD2;
+ if( GetKeyState( VK_RMENU ) & 0x8000 )
+ tmpCode |= MODKEY_RMOD2;
+
+ if( tmpCode < nLastModKeyCode )
+ {
+ aModEvt.mnModKeyCode = nLastModKeyCode;
+ nLastModKeyCode = 0;
+ bWaitForModKeyRelease = true;
+ }
+ else
+ {
+ if( !bWaitForModKeyRelease )
+ nLastModKeyCode = tmpCode;
+ }
+
+ if( !tmpCode )
+ bWaitForModKeyRelease = false;
+
+ return pFrame->CallCallback( SALEVENT_KEYMODCHANGE, &aModEvt );
+ }
+ else
+ {
+ SalKeyEvent aKeyEvt;
+ sal_uInt16 nEvent;
+ MSG aCharMsg;
+ BOOL bCharPeek = FALSE;
+ UINT nCharMsg = WM_CHAR;
+ sal_Bool bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
+
+ nLastModKeyCode = 0; // make sure no modkey messages are sent if they belong to a hotkey (see above)
+ aKeyEvt.mnCharCode = 0;
+ aKeyEvt.mnCode = 0;
+
+ aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
+ if ( !bKeyUp )
+ {
+ // check for charcode
+ // Mit Hilfe von PeekMessage holen wir uns jetzt die
+ // zugehoerige WM_CHAR Message, wenn vorhanden.
+ // Diese WM_CHAR Message steht immer am Anfang der
+ // Messagequeue. Ausserdem ist sichergestellt, dass immer
+ // nur eine WM_CHAR Message in der Queue steht.
+ bCharPeek = ImplPeekMessage( &aCharMsg, hWnd,
+ WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD );
+ if ( bCharPeek && (nDeadChar == aCharMsg.wParam) )
+ {
+ bCharPeek = FALSE;
+ nDeadChar = 0;
+
+ if ( wParam == VK_BACK )
+ {
+ ImplPeekMessage( &aCharMsg, hWnd,
+ nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
+ return 0;
+ }
+ }
+ else
+ {
+ if ( !bCharPeek )
+ {
+ bCharPeek = ImplPeekMessage( &aCharMsg, hWnd,
+ WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD );
+ nCharMsg = WM_SYSCHAR;
+ }
+ }
+ if ( bCharPeek )
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam );
+ else
+ aKeyEvt.mnCharCode = 0;
+
+ nLastChar = aKeyEvt.mnCharCode;
+ nLastVKChar = wParam;
+ }
+ else
+ {
+ if ( wParam == nLastVKChar )
+ {
+ aKeyEvt.mnCharCode = nLastChar;
+ nLastChar = 0;
+ nLastVKChar = 0;
+ }
+ }
+
+ if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode )
+ {
+ if ( bKeyUp )
+ nEvent = SALEVENT_KEYUP;
+ else
+ nEvent = SALEVENT_KEYINPUT;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnRepeat = nRepeat;
+
+ if( (nModCode & (KEY_MOD1|KEY_MOD2)) == (KEY_MOD1|KEY_MOD2) &&
+ aKeyEvt.mnCharCode )
+ {
+ // this is actually AltGr and should not be handled as Alt
+ aKeyEvt.mnCode &= ~(KEY_MOD1|KEY_MOD2);
+ }
+
+ bIgnoreCharMsg = bCharPeek ? TRUE : FALSE;
+ long nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
+ // independent part only reacts on keyup but Windows does not send
+ // keyup for VK_HANJA
+ if( aKeyEvt.mnCode == KEY_HANGUL_HANJA )
+ nRet = pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+
+ bIgnoreCharMsg = FALSE;
+
+ // char-message, than remove or ignore
+ if ( bCharPeek )
+ {
+ nDeadChar = 0;
+ if ( nRet )
+ {
+ ImplPeekMessage( &aCharMsg, hWnd,
+ nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
+ }
+ else
+ bIgnoreCharMsg = TRUE;
+ }
+
+ return nRet;
+ }
+ else
+ return 0;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+long ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ sal_uInt16 nRepeat = LOWORD( lParam )-1;
+ sal_uInt16 nModCode = 0;
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ if ( GetKeyState( VK_MENU ) & 0x8000 )
+ nModCode |= KEY_MOD2;
+
+ if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) )
+ {
+ SalKeyEvent aKeyEvt;
+ sal_uInt16 nEvent;
+ sal_Bool bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
+
+ // convert KeyCode
+ aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
+ aKeyEvt.mnCharCode = 0;
+
+ if ( aKeyEvt.mnCode )
+ {
+ if ( bKeyUp )
+ nEvent = SALEVENT_KEYUP;
+ else
+ nEvent = SALEVENT_KEYINPUT;
+
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnRepeat = nRepeat;
+ long nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
+ return nRet;
+ }
+ else
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ sal_uInt16 nRepeat = LOWORD( lParam )-1;
+ sal_uInt16 nModCode = 0;
+ sal_uInt16 cKeyCode = (sal_uInt16)wParam;
+
+ // determine modifiers
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ nModCode |= KEY_MOD2;
+
+ // KeyEvent zusammenbauen
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
+ aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
+ else if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-65);
+ else if ( (cKeyCode >= 97) && (cKeyCode <= 122) )
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
+ else
+ aKeyEvt.mnCode = 0;
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, cKeyCode );
+ aKeyEvt.mnRepeat = nRepeat;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static bool ImplHandlePaintMsg( HWND hWnd )
+{
+ sal_Bool bMutex = FALSE;
+ if ( ImplSalYieldMutexTryToAcquire() )
+ bMutex = TRUE;
+
+ // if we don't get the mutex, we can also change the clip region,
+ // because other threads doesn't use the mutex from the main
+ // thread --> see GetGraphics()
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ // Clip-Region muss zurueckgesetzt werden, da wir sonst kein
+ // ordentliches Bounding-Rectangle bekommen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ SelectClipRgn( pFrame->mpGraphics->mhDC, 0 );
+
+ // Laut Window-Doku soll man erst abfragen, ob ueberhaupt eine
+ // Paint-Region anliegt
+ if ( GetUpdateRect( hWnd, NULL, FALSE ) )
+ {
+ // Call BeginPaint/EndPaint to query the rect and send
+ // this Notofication to rect
+ RECT aUpdateRect;
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ CopyRect( &aUpdateRect, &aPs.rcPaint );
+
+ // Paint
+ // ClipRegion wieder herstellen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ {
+ SelectClipRgn( pFrame->mpGraphics->mhDC,
+ pFrame->mpGraphics->mhRegion );
+ }
+
+ if ( bMutex )
+ {
+ SalPaintEvent aPEvt( aUpdateRect.left, aUpdateRect.top, aUpdateRect.right-aUpdateRect.left, aUpdateRect.bottom-aUpdateRect.top, pFrame->mbPresentation );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ else
+ {
+ RECT* pRect = new RECT;
+ CopyRect( pRect, &aUpdateRect );
+ ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 );
+ }
+ EndPaint( hWnd, &aPs );
+ }
+ else
+ {
+ // ClipRegion wieder herstellen
+ if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion )
+ {
+ SelectClipRgn( pFrame->mpGraphics->mhDC,
+ pFrame->mpGraphics->mhRegion );
+ }
+ }
+ }
+
+ if ( bMutex )
+ ImplSalYieldMutexRelease();
+
+ return bMutex ? true : false;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandlePaintMsg2( HWND hWnd, RECT* pRect )
+{
+ // Paint
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top );
+ pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
+ }
+ ImplSalYieldMutexRelease();
+ delete pRect;
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTPAINT, (WPARAM)pRect, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect )
+{
+ // calculate and set frame geometry of a maximized window - useful if the window is still hidden
+
+ // dualmonitor support:
+ // Get screensize of the monitor whith the mouse pointer
+
+ RECT aRectMouse;
+ if( ! pParentRect )
+ {
+ POINT pt;
+ GetCursorPos( &pt );
+ aRectMouse.left = pt.x;
+ aRectMouse.top = pt.y;
+ aRectMouse.right = pt.x+2;
+ aRectMouse.bottom = pt.y+2;
+ pParentRect = &aRectMouse;
+ }
+
+ RECT aRect;
+ ImplSalGetWorkArea( hWnd, &aRect, pParentRect );
+
+ // a maximized window has no other borders than the caption
+ pFrame->maGeometry.nLeftDecoration = pFrame->maGeometry.nRightDecoration = pFrame->maGeometry.nBottomDecoration = 0;
+ pFrame->maGeometry.nTopDecoration = pFrame->mbCaption ? GetSystemMetrics( SM_CYCAPTION ) : 0;
+
+ aRect.top += pFrame->maGeometry.nTopDecoration;
+ pFrame->maGeometry.nX = aRect.left;
+ pFrame->maGeometry.nY = aRect.top;
+ pFrame->maGeometry.nWidth = aRect.right - aRect.left;
+ pFrame->maGeometry.nHeight = aRect.bottom - aRect.top;
+}
+
+static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame )
+{
+ if( !pFrame )
+ return;
+
+ RECT aRect;
+ GetWindowRect( hWnd, &aRect );
+ memset(&pFrame->maGeometry, 0, sizeof(SalFrameGeometry) );
+
+ if ( IsIconic( hWnd ) )
+ return;
+
+ POINT aPt;
+ aPt.x=0;
+ aPt.y=0;
+ ClientToScreen(hWnd, &aPt);
+ int cx = aPt.x - aRect.left;
+ pFrame->maGeometry.nTopDecoration = aPt.y - aRect.top;
+
+ pFrame->maGeometry.nLeftDecoration = cx;
+ pFrame->maGeometry.nRightDecoration = cx;
+
+ pFrame->maGeometry.nX = aPt.x;
+ pFrame->maGeometry.nY = aPt.y;
+
+ RECT aInnerRect;
+ GetClientRect( hWnd, &aInnerRect );
+ if( aInnerRect.right )
+ {
+ // improve right decoration
+ aPt.x=aInnerRect.right;
+ aPt.y=aInnerRect.top;
+ ClientToScreen(hWnd, &aPt);
+ pFrame->maGeometry.nRightDecoration = aRect.right - aPt.x;
+ }
+ if( aInnerRect.bottom ) // may be zero if window was not shown yet
+ pFrame->maGeometry.nBottomDecoration += aRect.bottom - aPt.y - aInnerRect.bottom;
+ else
+ // bottom border is typically the same as left/right
+ pFrame->maGeometry.nBottomDecoration = pFrame->maGeometry.nLeftDecoration;
+
+ int nWidth = aRect.right - aRect.left
+ - pFrame->maGeometry.nRightDecoration - pFrame->maGeometry.nLeftDecoration;
+ int nHeight = aRect.bottom - aRect.top
+ - pFrame->maGeometry.nBottomDecoration - pFrame->maGeometry.nTopDecoration;
+ // clamp to zero
+ pFrame->maGeometry.nHeight = nHeight < 0 ? 0 : nHeight;
+ pFrame->maGeometry.nWidth = nWidth < 0 ? 0 : nWidth;
+ pFrame->updateScreenNumber();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallMoveHdl( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_MOVE, 0 );
+ // Um doppelte Paints von VCL und SAL zu vermeiden
+ //if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ // UpdateWindow( hWnd );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallClosePopupsHdl( HWND hWnd )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_CLOSEPOPUPS, 0 );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleMoveMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ if ( GetWindowStyle( hWnd ) & WS_VISIBLE )
+ pFrame->mbDefPos = FALSE;
+
+ // Gegen moegliche Rekursionen sichern
+ if ( !pFrame->mbInMoveMsg )
+ {
+ // Fenster im FullScreenModus wieder einpassen
+ pFrame->mbInMoveMsg = TRUE;
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ pFrame->mbInMoveMsg = FALSE;
+ }
+
+ // Status merken
+ ImplSaveFrameState( pFrame );
+
+ // Call Hdl
+ //#93851 if we call this handler, VCL floating windows are not updated correctly
+ ImplCallMoveHdl( hWnd );
+
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTMOVE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplCallSizeHdl( HWND hWnd )
+{
+ // Da Windows diese Messages auch senden kann, muss hier auch die
+ // Solar-Semaphore beruecksichtigt werden
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_RESIZE, 0 );
+ // Um doppelte Paints von VCL und SAL zu vermeiden
+ if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ UpdateWindow( hWnd );
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTCALLSIZE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSizeMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ if ( (wParam != SIZE_MAXSHOW) && (wParam != SIZE_MAXHIDE) )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ UpdateFrameGeometry( hWnd, pFrame );
+
+ pFrame->mnWidth = (int)LOWORD(lParam);
+ pFrame->mnHeight = (int)HIWORD(lParam);
+ // Status merken
+ ImplSaveFrameState( pFrame );
+ // Call Hdl
+ ImplCallSizeHdl( hWnd );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleFocusMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && !WinSalFrame::mbInReparent )
+ {
+ // Query the actual status
+ if ( ::GetFocus() == hWnd )
+ {
+ if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
+ UpdateWindow( hWnd );
+
+ // Feststellen, ob wir IME unterstuetzen
+ if ( pFrame->mbIME && pFrame->mhDefIMEContext )
+ {
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
+
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+
+ pFrame->CallCallback( SALEVENT_GETFOCUS, 0 );
+ }
+ else
+ {
+ pFrame->CallCallback( SALEVENT_LOSEFOCUS, 0 );
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SAL_MSG_POSTFOCUS, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleCloseMsg( HWND hWnd )
+{
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_CLOSE, 0 );
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, WM_CLOSE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+static long ImplHandleShutDownMsg( HWND hWnd )
+{
+ ImplSalYieldMutexAcquireWithWait();
+ long nRet = 0;
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ nRet = pFrame->CallCallback( SALEVENT_SHUTDOWN, 0 );
+ }
+ ImplSalYieldMutexRelease();
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam )
+{
+ sal_uInt16 nSalEvent = SALEVENT_SETTINGSCHANGED;
+
+ if ( nMsg == WM_DEVMODECHANGE )
+ nSalEvent = SALEVENT_PRINTERCHANGED;
+ else if ( nMsg == WM_DISPLAYCHANGE )
+ nSalEvent = SALEVENT_DISPLAYCHANGED;
+ else if ( nMsg == WM_FONTCHANGE )
+ nSalEvent = SALEVENT_FONTCHANGED;
+ else if ( nMsg == WM_TIMECHANGE )
+ nSalEvent = SALEVENT_DATETIMECHANGED;
+ else if ( nMsg == WM_WININICHANGE )
+ {
+ if ( lParam )
+ {
+ if ( ImplSalWICompareAscii( (const wchar_t*)lParam, "devices" ) == 0 )
+ nSalEvent = SALEVENT_PRINTERCHANGED;
+ }
+ }
+
+ if ( nMsg == WM_SETTINGCHANGE )
+ {
+ if ( wParam == SPI_SETWHEELSCROLLLINES )
+ aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
+ else if( wParam == SPI_SETWHEELSCROLLCHARS )
+ aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
+ }
+
+ if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
+ ImplUpdateSysColorEntries();
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ if ( (nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE) )
+ {
+ if ( pFrame->mbFullScreen )
+ ImplSalFrameFullScreenPos( pFrame );
+ }
+
+ pFrame->CallCallback( nSalEvent, 0 );
+ }
+
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam )
+{
+ ImplSalYieldMutexAcquireWithWait();
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ pFrame->CallCallback( SALEVENT_USEREVENT, (void*)lParam );
+ }
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleForcePalette( HWND hWnd )
+{
+ SalData* pSalData = GetSalData();
+ HPALETTE hPal = pSalData->mhDitherPal;
+ if ( hPal )
+ {
+ if ( !ImplSalYieldMutexTryToAcquire() )
+ {
+ ImplPostMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
+ return;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mpGraphics )
+ {
+ WinSalGraphics* pGraphics = pFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, FALSE );
+ if ( RealizePalette( pGraphics->mhDC ) )
+ {
+ InvalidateRect( hWnd, NULL, FALSE );
+ UpdateWindow( hWnd );
+ pFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static LRESULT ImplHandlePalette( sal_Bool bFrame, HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ SalData* pSalData = GetSalData();
+ HPALETTE hPal = pSalData->mhDitherPal;
+ if ( !hPal )
+ return 0;
+
+ rDef = FALSE;
+ if ( pSalData->mbInPalChange )
+ return 0;
+
+ if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
+ {
+ if ( (HWND)wParam == hWnd )
+ return 0;
+ }
+
+ sal_Bool bReleaseMutex = FALSE;
+ if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) )
+ {
+ // Da Windows diese Messages auch sendet, muss hier auch die
+ // Solar-Semaphore beruecksichtigt werden
+ if ( ImplSalYieldMutexTryToAcquire() )
+ bReleaseMutex = TRUE;
+ else if ( nMsg == WM_QUERYNEWPALETTE )
+ ImplPostMessage( hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam );
+ else /* ( nMsg == WM_PALETTECHANGED ) */
+ ImplPostMessage( hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam );
+ }
+
+ WinSalVirtualDevice*pTempVD;
+ WinSalFrame* pTempFrame;
+ WinSalGraphics* pGraphics;
+ HDC hDC;
+ HPALETTE hOldPal;
+ UINT nCols;
+ sal_Bool bStdDC;
+ sal_Bool bUpdate;
+
+ pSalData->mbInPalChange = TRUE;
+
+ // Alle Paletten in VirDevs und Frames zuruecksetzen
+ pTempVD = pSalData->mpFirstVD;
+ while ( pTempVD )
+ {
+ pGraphics = pTempVD->mpGraphics;
+ if ( pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC,
+ pGraphics->mhDefPal,
+ TRUE );
+ }
+ pTempVD = pTempVD->mpNext;
+ }
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC,
+ pGraphics->mhDefPal,
+ TRUE );
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+
+ // Palette neu realizen
+ WinSalFrame* pFrame = NULL;
+ if ( bFrame )
+ pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mpGraphics )
+ {
+ hDC = pFrame->mpGraphics->mhDC;
+ bStdDC = TRUE;
+ }
+ else
+ {
+ hDC = GetDC( hWnd );
+ bStdDC = FALSE;
+ }
+ UnrealizeObject( hPal );
+ hOldPal = SelectPalette( hDC, hPal, TRUE );
+ nCols = RealizePalette( hDC );
+ bUpdate = nCols != 0;
+ if ( !bStdDC )
+ {
+ SelectPalette( hDC, hOldPal, TRUE );
+ ReleaseDC( hWnd, hDC );
+ }
+
+ // Alle Paletten in VirDevs und Frames neu setzen
+ pTempVD = pSalData->mpFirstVD;
+ while ( pTempVD )
+ {
+ pGraphics = pTempVD->mpGraphics;
+ if ( pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, TRUE );
+ RealizePalette( pGraphics->mhDC );
+ }
+ pTempVD = pTempVD->mpNext;
+ }
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ if ( pTempFrame != pFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ SelectPalette( pGraphics->mhDC, hPal, TRUE );
+ if ( RealizePalette( pGraphics->mhDC ) )
+ bUpdate = TRUE;
+ }
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+
+ // Wenn sich Farben geaendert haben, dann die Fenster updaten
+ if ( bUpdate )
+ {
+ pTempFrame = pSalData->mpFirstFrame;
+ while ( pTempFrame )
+ {
+ pGraphics = pTempFrame->mpGraphics;
+ if ( pGraphics && pGraphics->mhDefPal )
+ {
+ InvalidateRect( pTempFrame->mhWnd, NULL, FALSE );
+ UpdateWindow( pTempFrame->mhWnd );
+ pTempFrame->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
+ }
+ pTempFrame = pTempFrame->mpNextFrame;
+ }
+ }
+
+ pSalData->mbInPalChange = FALSE;
+
+ if ( bReleaseMutex )
+ ImplSalYieldMutexRelease();
+
+ if ( nMsg == WM_PALETTECHANGED )
+ return 0;
+ else
+ return nCols;
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplHandleMinMax( HWND hWnd, LPARAM lParam )
+{
+ int bRet = FALSE;
+
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ MINMAXINFO* pMinMax = (MINMAXINFO*)lParam;
+
+ if ( pFrame->mbFullScreen )
+ {
+ int nX;
+ int nY;
+ int nDX;
+ int nDY;
+ ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY );
+
+ if ( pMinMax->ptMaxPosition.x > nX )
+ pMinMax->ptMaxPosition.x = nX;
+ if ( pMinMax->ptMaxPosition.y > nY )
+ pMinMax->ptMaxPosition.y = nY;
+
+ if ( pMinMax->ptMaxSize.x < nDX )
+ pMinMax->ptMaxSize.x = nDX;
+ if ( pMinMax->ptMaxSize.y < nDY )
+ pMinMax->ptMaxSize.y = nDY;
+ if ( pMinMax->ptMaxTrackSize.x < nDX )
+ pMinMax->ptMaxTrackSize.x = nDX;
+ if ( pMinMax->ptMaxTrackSize.y < nDY )
+ pMinMax->ptMaxTrackSize.y = nDY;
+
+ pMinMax->ptMinTrackSize.x = nDX;
+ pMinMax->ptMinTrackSize.y = nDY;
+
+ bRet = TRUE;
+ }
+
+ if ( pFrame->mnMinWidth || pFrame->mnMinHeight )
+ {
+ int nWidth = pFrame->mnMinWidth;
+ int nHeight = pFrame->mnMinHeight;
+
+ ImplSalAddBorder( pFrame, nWidth, nHeight );
+
+ if ( pMinMax->ptMinTrackSize.x < nWidth )
+ pMinMax->ptMinTrackSize.x = nWidth;
+ if ( pMinMax->ptMinTrackSize.y < nHeight )
+ pMinMax->ptMinTrackSize.y = nHeight;
+ }
+
+ if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight )
+ {
+ int nWidth = pFrame->mnMaxWidth;
+ int nHeight = pFrame->mnMaxHeight;
+
+ ImplSalAddBorder( pFrame, nWidth, nHeight );
+
+ if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation
+ {
+ if ( pMinMax->ptMaxTrackSize.x > nWidth )
+ pMinMax->ptMaxTrackSize.x = nWidth;
+ if ( pMinMax->ptMaxTrackSize.y > nHeight )
+ pMinMax->ptMaxTrackSize.y = nHeight;
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+
+ return bRet;
+}
+
+// -----------------------------------------------------------------------
+
+// retrieves the SalMenuItem pointer from a hMenu
+// the pointer is stored in every item, so if no position
+// is specified we just use the first item (ie, pos=0)
+// if bByPosition is FALSE then nPos denotes a menu id instead of a position
+static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, sal_Bool bByPosition=TRUE )
+{
+ DWORD err=0;
+
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) )
+ err = GetLastError();
+
+ return (WinSalMenuItem *) mi.dwItemData;
+}
+
+// returns the index of the currently selected item if any or -1
+static int ImplGetSelectedIndex( HMENU hMenu )
+{
+ DWORD err=0;
+
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_STATE;
+ int n = GetMenuItemCount( hMenu );
+ if( n != -1 )
+ {
+ for(int i=0; i<n; i++ )
+ {
+ if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) )
+ err = GetLastError();
+ else
+ {
+ if( mi.fState & MFS_HILITE )
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static int ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = MNC_IGNORE;
+ HMENU hMenu = (HMENU) lParam;
+ String aMnemonic;
+ aMnemonic.AssignAscii("&");
+ aMnemonic.Append( (sal_Unicode) LOWORD(wParam) );
+ aMnemonic.ToLowerAscii(); // we only have ascii mnemonics
+
+ // search the mnemonic in the current menu
+ int nItemCount = GetMenuItemCount( hMenu );
+ int nFound = 0;
+ int idxFound = -1;
+ int idxSelected = ImplGetSelectedIndex( hMenu );
+ int idx = idxSelected != -1 ? idxSelected+1 : 0; // if duplicate mnemonics cycle through menu
+ for( int i=0; i< nItemCount; i++, idx++ )
+ {
+ WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount );
+ if( !pSalMenuItem )
+ continue;
+ String aStr = pSalMenuItem->mText;
+ aStr.ToLowerAscii();
+ if( aStr.Search( aMnemonic ) != STRING_NOTFOUND)
+ {
+ if( idxFound == -1 )
+ idxFound = idx % nItemCount;
+ if( nFound++ )
+ break; // duplicate found
+ }
+ }
+ if( nFound == 1 )
+ nRet = MAKELRESULT( idxFound, MNC_EXECUTE );
+ else
+ // duplicate mnemonics, just select the next occurence
+ nRet = MAKELRESULT( idxFound, MNC_SELECT );
+
+ return nRet;
+}
+
+static int ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = 0;
+ if( !wParam )
+ {
+ // request was sent by a menu
+ nRet = 1;
+ MEASUREITEMSTRUCT *pMI = (LPMEASUREITEMSTRUCT) lParam;
+ if( pMI->CtlType != ODT_MENU )
+ return 0;
+
+ WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pMI->itemData;
+ if( !pSalMenuItem )
+ return 0;
+
+ HDC hdc = GetDC( hWnd );
+ SIZE strSize;
+
+ NONCLIENTMETRICS ncm;
+ memset( &ncm, 0, sizeof(ncm) );
+ ncm.cbSize = sizeof( ncm );
+ SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 );
+
+ // Assume every menu item can be default and printed bold
+ //ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ HFONT hfntOld = (HFONT) SelectObject(hdc, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
+
+ // menu text and accelerator
+ String aStr(pSalMenuItem->mText.GetBuffer() );
+ if( pSalMenuItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii(" ");
+ aStr.Append( pSalMenuItem->mAccelText );
+ }
+ GetTextExtentPoint32W( hdc, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSize );
+
+ // image
+ Size bmpSize( 16, 16 );
+ //if( !!pSalMenuItem->maBitmap )
+ // bmpSize = pSalMenuItem->maBitmap.GetSizePixel();
+
+ // checkmark
+ Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) );
+
+ pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx;
+ pMI->itemHeight = Max( Max( checkSize.Height(), bmpSize.Height() ), strSize.cy );
+ pMI->itemHeight += 4;
+
+ DeleteObject( SelectObject(hdc, hfntOld) );
+ ReleaseDC( hWnd, hdc );
+ }
+
+ return nRet;
+}
+
+static int ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam )
+{
+ int nRet = 0;
+ DWORD err = 0;
+ if( !wParam )
+ {
+ // request was sent by a menu
+ nRet = 1;
+ DRAWITEMSTRUCT *pDI = (LPDRAWITEMSTRUCT) lParam;
+ if( pDI->CtlType != ODT_MENU )
+ return 0;
+
+ WinSalMenuItem *pSalMenuItem = (WinSalMenuItem *) pDI->itemData;
+ if( !pSalMenuItem )
+ return 0;
+
+ COLORREF clrPrevText, clrPrevBkgnd;
+ HFONT hfntOld;
+ HBRUSH hbrOld;
+ sal_Bool fChecked = (pDI->itemState & ODS_CHECKED) ? TRUE : FALSE;
+ sal_Bool fSelected = (pDI->itemState & ODS_SELECTED) ? TRUE : FALSE;
+ sal_Bool fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED)) ? TRUE : FALSE;
+
+ // Set the appropriate foreground and background colors.
+ RECT aRect = pDI->rcItem;
+
+ clrPrevBkgnd = SetBkColor( pDI->hDC, GetSysColor( COLOR_MENU ) );
+
+ if ( fDisabled )
+ clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) );
+ else
+ clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
+
+ DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU );
+ if ( fSelected )
+ clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
+ else
+ clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
+
+ hbrOld = (HBRUSH)SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) );
+
+ // Fill background
+ if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY ))
+ err = GetLastError();
+
+ int lineHeight = aRect.bottom-aRect.top;
+
+ int x = aRect.left;
+ int y = aRect.top;
+
+ int checkWidth = GetSystemMetrics( SM_CXMENUCHECK );
+ int checkHeight = GetSystemMetrics( SM_CYMENUCHECK );
+ if( fChecked )
+ {
+ RECT r;
+ r.left = 0;
+ r.top = 0;
+ r.right = checkWidth;
+ r.bottom = checkWidth;
+ HDC memDC = CreateCompatibleDC( pDI->hDC );
+ HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight );
+ HBITMAP hOldBmp = (HBITMAP) SelectObject( memDC, memBmp );
+ DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK );
+ BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND );
+ DeleteObject( SelectObject( memDC, hOldBmp ) );
+ DeleteDC( memDC );
+ }
+ x += checkWidth+3;
+
+ //Size bmpSize = aBitmap.GetSizePixel();
+ Size bmpSize(16, 16);
+ if( !!pSalMenuItem->maBitmap )
+ {
+ Bitmap aBitmap( pSalMenuItem->maBitmap );
+
+ // set transparent pixels to background color
+ if( fDisabled )
+ colBackground = RGB(255,255,255);
+ aBitmap.Replace( Color( COL_LIGHTMAGENTA ),
+ Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ), 0);
+
+ WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetImpBitmap()->ImplGetSalBitmap());
+ HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB();
+
+ if( hDrawDIB )
+ {
+ PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB );
+ PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
+ PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
+ pSalBmp->ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
+
+ HBITMAP hBmp = CreateDIBitmap( pDI->hDC, pBIH, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
+ GlobalUnlock( hDrawDIB );
+
+ HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
+ DrawStateW( pDI->hDC, (HBRUSH)hbrIcon, (DRAWSTATEPROC)NULL, (LPARAM)hBmp, (WPARAM)0,
+ x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(),
+ DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
+
+ DeleteObject( hbrIcon );
+ DeleteObject( hBmp );
+ }
+
+ }
+ x += bmpSize.Width() + 3;
+ aRect.left = x;
+
+ NONCLIENTMETRICS ncm;
+ memset( &ncm, 0, sizeof(ncm) );
+ ncm.cbSize = sizeof( ncm );
+ SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0 );
+
+ // Print default menu entry with bold font
+ //if ( pDI->itemState & ODS_DEFAULT )
+ // ncm.lfMenuFont.lfWeight = FW_BOLD;
+
+ hfntOld = (HFONT) SelectObject(pDI->hDC, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
+
+ SIZE strSize;
+ String aStr( pSalMenuItem->mText.GetBuffer() );
+ GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSize );
+
+ if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL,
+ (LPARAM)(LPWSTR) aStr.GetBuffer(),
+ (WPARAM)0, aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0,
+ DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
+ err = GetLastError();
+
+ if( pSalMenuItem->mAccelText.Len() )
+ {
+ SIZE strSizeA;
+ aStr = pSalMenuItem->mAccelText;
+ GetTextExtentPoint32W( pDI->hDC, (LPWSTR) aStr.GetBuffer(),
+ aStr.Len(), &strSizeA );
+ TEXTMETRIC tm;
+ GetTextMetrics( pDI->hDC, &tm );
+
+ // position the accelerator string to the right but leave space for the
+ // (potential) submenu arrow (tm.tmMaxCharWidth)
+ if(!DrawStateW( pDI->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL,
+ (LPARAM)(LPWSTR) aStr.GetBuffer(),
+ (WPARAM)0, aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0,
+ DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
+ err = GetLastError();
+ }
+
+ // Restore the original font and colors.
+ DeleteObject( SelectObject( pDI->hDC, hbrOld ) );
+ DeleteObject( SelectObject( pDI->hDC, hfntOld) );
+ SetTextColor(pDI->hDC, clrPrevText);
+ SetBkColor(pDI->hDC, clrPrevBkgnd);
+ }
+ return nRet;
+}
+
+static int ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM )
+{
+ // Menu activation
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ HMENU hMenu = (HMENU) wParam;
+ // WORD nPos = LOWORD (lParam);
+ // sal_Bool bWindowMenu = (sal_Bool) HIWORD(lParam);
+
+ // Send activate and deactivate together, so we have not keep track of opened menues
+ // this will be enough to have the menues updated correctly
+ SalMenuEvent aMenuEvt;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ long nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt );
+ if( nRet )
+ nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt );
+ if( nRet )
+ pFrame->mLastActivatedhMenu = hMenu;
+
+ return (nRet!=0);
+}
+
+static int ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ // Menu selection
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ WORD nId = LOWORD(wParam); // menu item or submenu index
+ WORD nFlags = HIWORD(wParam);
+ HMENU hMenu = (HMENU) lParam;
+
+ // check if we have to process the message
+ if( !GetSalData()->IsKnownMenuHandle( hMenu ) )
+ return 0;
+
+ sal_Bool bByPosition = FALSE;
+ if( nFlags & MF_POPUP )
+ bByPosition = TRUE;
+
+ long nRet = 0;
+ if ( hMenu && !pFrame->mLastActivatedhMenu )
+ {
+ // we never activated a menu (ie, no WM_INITMENUPOPUP has occured yet)
+ // which means this must be the menubar -> send activation/deactivation
+ SalMenuEvent aMenuEvt;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUACTIVATE, &aMenuEvt );
+ if( nRet )
+ nRet = pFrame->CallCallback( SALEVENT_MENUDEACTIVATE, &aMenuEvt );
+ if( nRet )
+ pFrame->mLastActivatedhMenu = hMenu;
+ }
+
+ if( !hMenu && nFlags == 0xFFFF )
+ {
+ // all menus are closed, reset activation logic
+ pFrame->mLastActivatedhMenu = NULL;
+ }
+
+ if( hMenu )
+ {
+ // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection
+ // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later
+ // so we must not overwrite it in this case
+ pFrame->mSelectedhMenu = hMenu;
+
+ // send highlight event
+ if( nFlags & MF_POPUP )
+ {
+ // submenu selected
+ // wParam now carries an index instead of an id -> retrieve id
+ MENUITEMINFOW mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_ID;
+ if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) )
+ nId = sal::static_int_cast<WORD>(mi.wID);
+ }
+
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = nId;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, FALSE );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUHIGHLIGHT, &aMenuEvt );
+ }
+
+ return (nRet != 0);
+}
+
+static int ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ long nRet = 0;
+ if( !HIWORD(wParam) )
+ {
+ // Menu command
+ WORD nId = LOWORD(wParam);
+ if( nId ) // zero for separators
+ {
+ SalMenuEvent aMenuEvt;
+ aMenuEvt.mnId = nId;
+ WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, FALSE );
+ if( pSalMenuItem )
+ aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
+ else
+ aMenuEvt.mpMenu = NULL;
+
+ nRet = pFrame->CallCallback( SALEVENT_MENUCOMMAND, &aMenuEvt );
+ }
+ }
+ return (nRet != 0);
+}
+
+static int ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( !pFrame )
+ return 0;
+
+ WPARAM nCommand = wParam & 0xFFF0;
+
+ if ( pFrame->mbFullScreen )
+ {
+ BOOL bMaximize = IsZoomed( pFrame->mhWnd );
+ BOOL bMinimize = IsIconic( pFrame->mhWnd );
+ if ( (nCommand == SC_SIZE) ||
+ (!bMinimize && (nCommand == SC_MOVE)) ||
+ (!bMaximize && (nCommand == SC_MAXIMIZE)) ||
+ (bMaximize && (nCommand == SC_RESTORE)) )
+ {
+ MessageBeep( 0 );
+ return TRUE;
+ }
+ }
+
+ if ( nCommand == SC_KEYMENU )
+ {
+ // do not process SC_KEYMENU if we have a native menu
+ // Windows should handle this
+ if( GetMenu( hWnd ) )
+ return FALSE;
+
+ // Hier verarbeiten wir nur KeyMenu-Events fuer Alt um
+ // den MenuBar zu aktivieren, oder wenn ein SysChild-Fenster
+ // den Focus hat, da diese Alt+Tasten-Kombinationen nur
+ // ueber diesen Event verarbeitet werden
+ if ( !LOWORD( lParam ) )
+ {
+ // Nur ausloesen, wenn keine weitere Taste gedrueckt ist. Im
+ // Gegensatz zur Doku wird in der X-Koordinaate der CharCode
+ // geliefert, der zusaetzlich gedrueckt ist
+ // Also 32 fuer Space, 99 fuer c, 100 fuer d, ...
+ // Da dies nicht dokumentiert ist, fragen wir vorsichtshalber
+ // auch den Status der Space-Taste ab
+ if ( GetKeyState( VK_SPACE ) & 0x8000 )
+ return 0;
+
+ // Damit nicht bei Alt+Maustaste auch der MenuBar aktiviert wird
+ if ( (GetKeyState( VK_LBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_RBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_MBUTTON ) & 0x8000) ||
+ (GetKeyState( VK_SHIFT ) & 0x8000) )
+ return 1;
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ aKeyEvt.mnCode = KEY_MENU;
+ aKeyEvt.mnCharCode = 0;
+ aKeyEvt.mnRepeat = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return (nRet != 0);
+ }
+ else
+ {
+ // Testen, ob ein SysChild den Focus hat
+ HWND hFocusWnd = ::GetFocus();
+ if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) )
+ {
+ char cKeyCode = (char)(unsigned char)LOWORD( lParam );
+ // LowerCase
+ if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
+ cKeyCode += 32;
+ // Wir nehmen nur 0-9 und A-Z, alle anderen Tasten muessen durch
+ // den Hook vom SalObj verarbeitet werden
+ if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) ||
+ ((cKeyCode >= 97) && (cKeyCode <= 122)) )
+ {
+ sal_uInt16 nModCode = 0;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nModCode |= KEY_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nModCode |= KEY_MOD1;
+ nModCode |= KEY_MOD2;
+
+ SalKeyEvent aKeyEvt;
+ aKeyEvt.mnTime = GetMessageTime();
+ if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
+ aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
+ else
+ aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
+ aKeyEvt.mnCode |= nModCode;
+ aKeyEvt.mnCharCode = cKeyCode;
+ aKeyEvt.mnRepeat = 0;
+ long nRet = pFrame->CallCallback( SALEVENT_KEYINPUT, &aKeyEvt );
+ pFrame->CallCallback( SALEVENT_KEYUP, &aKeyEvt );
+ return (nRet != 0);
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam )
+{
+ ImplSalYieldMutexAcquireWithWait();
+
+ // Feststellen, ob wir IME unterstuetzen
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbIME && pFrame->mhDefIMEContext )
+ {
+ HKL hKL = (HKL)lParam;
+ UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
+
+ pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
+ pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
+ pFrame->mbHandleIME = !pFrame->mbSpezIME;
+ }
+
+ // trigger input language and codepage update
+ UINT nLang = pFrame->mnInputLang;
+ ImplUpdateInputLang( pFrame );
+
+ // notify change
+ if( nLang != pFrame->mnInputLang )
+ pFrame->CallCallback( SALEVENT_INPUTLANGUAGECHANGE, 0 );
+
+ ImplSalYieldMutexRelease();
+}
+
+// -----------------------------------------------------------------------
+
+static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC )
+{
+ COMPOSITIONFORM aForm;
+ memset( &aForm, 0, sizeof( aForm ) );
+
+ // Cursor-Position ermitteln und aus der die Default-Position fuer
+ // das Composition-Fenster berechnen
+ SalExtTextInputPosEvent aPosEvt;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt );
+ if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) )
+ aForm.dwStyle |= CFS_DEFAULT;
+ else
+ {
+ aForm.dwStyle |= CFS_POINT;
+ aForm.ptCurrentPos.x = aPosEvt.mnX;
+ aForm.ptCurrentPos.y = aPosEvt.mnY;
+ }
+ ImmSetCompositionWindow( hIMC, &aForm );
+
+ // Because not all IME's use this values, we create
+ // a Windows caret to force the Position from the IME
+ if ( GetFocus() == pFrame->mhWnd )
+ {
+ CreateCaret( pFrame->mhWnd, 0,
+ aPosEvt.mnWidth, aPosEvt.mnHeight );
+ SetCaretPos( aPosEvt.mnX, aPosEvt.mnY );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplHandleIMEStartComposition( HWND hWnd )
+{
+ sal_Bool bDef = TRUE;
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ {
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ ImmReleaseContext( hWnd, hIMC );
+ }
+
+ if ( pFrame->mbHandleIME )
+ {
+ if ( pFrame->mbAtCursorIME )
+ bDef = FALSE;
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplHandleIMECompositionInput( WinSalFrame* pFrame,
+ HIMC hIMC, LPARAM lParam )
+{
+ sal_Bool bDef = TRUE;
+
+ // Init Event
+ SalExtTextInputEvent aEvt;
+ aEvt.mnTime = GetMessageTime();
+ aEvt.mpTextAttr = NULL;
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbOnlyCursor = FALSE;
+ aEvt.mnCursorFlags = 0;
+
+ // If we get a result string, then we handle this input
+ if ( lParam & GCS_RESULTSTR )
+ {
+ bDef = FALSE;
+
+ LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, 0, 0 ) / sizeof( WCHAR );
+ if ( nTextLen >= 0 )
+ {
+ WCHAR* pTextBuf = new WCHAR[nTextLen];
+ ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf, nTextLen*sizeof( WCHAR ) );
+ aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen );
+ delete [] pTextBuf;
+ }
+
+ aEvt.mnCursorPos = aEvt.maText.Len();
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ }
+
+ // If the IME doesn't support OnSpot input, then there is nothing to do
+ if ( !pFrame->mbAtCursorIME )
+ return !bDef;
+
+ // If we get new Composition data, then we handle this new input
+ if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) ||
+ ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) )
+ {
+ bDef = FALSE;
+
+ sal_uInt16* pSalAttrAry = NULL;
+ LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 ) / sizeof( WCHAR );
+ if ( nTextLen > 0 )
+ {
+ WCHAR* pTextBuf = new WCHAR[nTextLen];
+ ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf, nTextLen*sizeof( WCHAR ) );
+ aEvt.maText = XubString( reinterpret_cast<const xub_Unicode*>(pTextBuf), (xub_StrLen)nTextLen );
+ delete [] pTextBuf;
+
+ BYTE* pAttrBuf = NULL;
+ LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, 0, 0 );
+ if ( nAttrLen > 0 )
+ {
+ pAttrBuf = new BYTE[nAttrLen];
+ ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf, nAttrLen );
+ }
+
+ if ( pAttrBuf )
+ {
+ xub_StrLen nTextLen = aEvt.maText.Len();
+ pSalAttrAry = new sal_uInt16[nTextLen];
+ memset( pSalAttrAry, 0, nTextLen*sizeof( sal_uInt16 ) );
+ for ( xub_StrLen i = 0; (i < nTextLen) && (i < nAttrLen); i++ )
+ {
+ BYTE nWinAttr = pAttrBuf[i];
+ sal_uInt16 nSalAttr;
+ if ( nWinAttr == ATTR_TARGET_CONVERTED )
+ {
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_BOLDUNDERLINE;
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE;
+ }
+ else if ( nWinAttr == ATTR_CONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE;
+ else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_HIGHLIGHT;
+ else if ( nWinAttr == ATTR_INPUT_ERROR )
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_REDTEXT | SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ else /* ( nWinAttr == ATTR_INPUT ) */
+ nSalAttr = SAL_EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE;
+ pSalAttrAry[i] = nSalAttr;
+ }
+
+ aEvt.mpTextAttr = pSalAttrAry;
+ delete [] pAttrBuf;
+ }
+ }
+
+ // Only when we get new composition data, we must send this event
+ if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) )
+ {
+ // End the mode, if the last character is deleted
+ if ( !nTextLen && !pFrame->mbCandidateMode )
+ {
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ else
+ {
+ // Because Cursor-Position and DeltaStart never updated
+ // from the korean input engine, we must handle this here
+ if ( lParam & CS_INSERTCHAR )
+ {
+ aEvt.mnCursorPos = nTextLen;
+ if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) )
+ aEvt.mnCursorPos--;
+ }
+ else
+ aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, 0, 0 ) );
+
+ if ( pFrame->mbCandidateMode )
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_INVISIBLE;
+ if ( lParam & CS_NOMOVECARET )
+ aEvt.mnCursorFlags |= SAL_EXTTEXTINPUT_CURSOR_OVERWRITE;
+
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ }
+ ImplUpdateIMECursorPos( pFrame, hIMC );
+ }
+
+ if ( pSalAttrAry )
+ delete [] pSalAttrAry;
+ }
+
+ return !bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplHandleIMEComposition( HWND hWnd, LPARAM lParam )
+{
+ sal_Bool bDef = TRUE;
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) )
+ {
+ // Wir restaurieren den Background-Modus bei jeder Texteingabe,
+ // da einige Tools wie RichWin uns diesen hin- und wieder umsetzen
+ if ( pFrame->mpGraphics &&
+ pFrame->mpGraphics->mhDC )
+ SetBkMode( pFrame->mpGraphics->mhDC, TRANSPARENT );
+ }
+
+ if ( pFrame && pFrame->mbHandleIME )
+ {
+ if ( !lParam )
+ {
+ SalExtTextInputEvent aEvt;
+ aEvt.mnTime = GetMessageTime();
+ aEvt.mpTextAttr = NULL;
+ aEvt.mnCursorPos = 0;
+ aEvt.mnDeltaStart = 0;
+ aEvt.mbOnlyCursor = FALSE;
+ aEvt.mnCursorFlags = 0;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUT, (void*)&aEvt );
+ pFrame->CallCallback( SALEVENT_ENDEXTTEXTINPUT, (void*)NULL );
+ }
+ else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) )
+ {
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) )
+ bDef = FALSE;
+
+ ImmReleaseContext( hWnd, hIMC );
+ }
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static sal_Bool ImplHandleIMEEndComposition( HWND hWnd )
+{
+ sal_Bool bDef = TRUE;
+
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbHandleIME )
+ {
+ if ( pFrame->mbAtCursorIME )
+ bDef = FALSE;
+ }
+
+ ImplSalYieldMutexRelease();
+
+ return bDef;
+}
+
+// -----------------------------------------------------------------------
+
+static boolean ImplHandleAppCommand( HWND hWnd, LPARAM lParam )
+{
+ sal_Int16 nCommand = 0;
+ switch( GET_APPCOMMAND_LPARAM(lParam) )
+ {
+ case APPCOMMAND_MEDIA_CHANNEL_DOWN: nCommand = MEDIA_COMMAND_CHANNEL_DOWN; break;
+ case APPCOMMAND_MEDIA_CHANNEL_UP: nCommand = MEDIA_COMMAND_CHANNEL_UP; break;
+ case APPCOMMAND_MEDIA_NEXTTRACK: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
+ case APPCOMMAND_MEDIA_PAUSE: nCommand = MEDIA_COMMAND_PAUSE; break;
+ case APPCOMMAND_MEDIA_PLAY: nCommand = MEDIA_COMMAND_PLAY; break;
+ case APPCOMMAND_MEDIA_PLAY_PAUSE: nCommand = MEDIA_COMMAND_PLAY_PAUSE; break;
+ case APPCOMMAND_MEDIA_PREVIOUSTRACK: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
+ case APPCOMMAND_MEDIA_RECORD: nCommand = MEDIA_COMMAND_RECORD; break;
+ case APPCOMMAND_MEDIA_REWIND: nCommand = MEDIA_COMMAND_REWIND; break;
+ case APPCOMMAND_MEDIA_STOP: nCommand = MEDIA_COMMAND_STOP; break;
+ case APPCOMMAND_MIC_ON_OFF_TOGGLE: nCommand = MEDIA_COMMAND_MIC_ON_OFF_TOGGLE; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_DOWN: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_DOWN; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_MUTE: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_MUTE; break;
+ case APPCOMMAND_MICROPHONE_VOLUME_UP: nCommand = MEDIA_COMMAND_MICROPHONE_VOLUME_UP; break;
+ case APPCOMMAND_VOLUME_DOWN: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
+ case APPCOMMAND_VOLUME_MUTE: nCommand = MEDIA_COMMAND_VOLUME_MUTE; break;
+ case APPCOMMAND_VOLUME_UP: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
+ break;
+ default:
+ return false;
+ }
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ Window *pWindow = pFrame ? pFrame->GetWindow() : NULL;
+
+ if( pWindow )
+ {
+ const Point aPoint;
+ CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
+ NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
+
+ if ( !ImplCallPreNotify( aNCmdEvt ) )
+ {
+ pWindow->Command( aCEvt );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam )
+{
+ if ( wParam == (WPARAM)IMN_OPENCANDIDATE )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame && pFrame->mbHandleIME &&
+ pFrame->mbAtCursorIME )
+ {
+ // Wir wollen den Cursor hiden
+ pFrame->mbCandidateMode = TRUE;
+ ImplHandleIMEComposition( hWnd, GCS_CURSORPOS );
+
+ HWND hWnd = pFrame->mhWnd;
+ HIMC hIMC = ImmGetContext( hWnd );
+ if ( hIMC )
+ {
+ LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, 0, 0 );
+ if ( nBufLen >= 1 )
+ {
+ SalExtTextInputPosEvent aPosEvt;
+ pFrame->CallCallback( SALEVENT_EXTTEXTINPUTPOS, (void*)&aPosEvt );
+
+ // Vertical !!!
+ CANDIDATEFORM aForm;
+ aForm.dwIndex = 0;
+ aForm.dwStyle = CFS_EXCLUDE;
+ aForm.ptCurrentPos.x = aPosEvt.mnX;
+ aForm.ptCurrentPos.y = aPosEvt.mnY+1;
+ aForm.rcArea.left = aPosEvt.mnX;
+ aForm.rcArea.top = aPosEvt.mnY;
+ aForm.rcArea.right = aForm.rcArea.left+aPosEvt.mnExtWidth+1;
+ aForm.rcArea.bottom = aForm.rcArea.top+aPosEvt.mnHeight+1;
+ ImmSetCandidateWindow( hIMC, &aForm );
+ }
+
+ ImmReleaseContext( hWnd, hIMC );
+ }
+ }
+
+ ImplSalYieldMutexRelease();
+ }
+ else if ( wParam == (WPARAM)IMN_CLOSECANDIDATE )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ if ( pFrame )
+ pFrame->mbCandidateMode = FALSE;
+ ImplSalYieldMutexRelease();
+ }
+}
+
+// -----------------------------------------------------------------------
+#if WINVER >= 0x0500
+
+static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam;
+ LRESULT nRet = 0;
+ SalSurroundingTextRequestEvent aEvt;
+ aEvt.maText = UniString();
+ aEvt.mnStart = aEvt.mnEnd = 0;
+
+ UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR );
+ if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 )
+ {
+ // This IME does not support reconversion.
+ return 0;
+ }
+
+ if( !pReconvertString )
+ {
+ // The first call for reconversion.
+ pFrame->CallCallback( SALEVENT_STARTRECONVERSION, (void*)NULL );
+
+ // Retrieve the surrounding text from the focused control.
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+
+ if( aEvt.maText.Len() == 0 )
+ {
+ return 0;
+ }
+
+ nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR);
+ }
+ else
+ {
+ // The second call for reconversion.
+
+ // Retrieve the surrounding text from the focused control.
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+ nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.Len() + 1) * sizeof(WCHAR);
+
+ pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
+ pReconvertString->dwStrLen = aEvt.maText.Len();
+ pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR);
+ pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart;
+ pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset;
+ pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen;
+
+ memcpy( (LPWSTR)(pReconvertString + 1), aEvt.maText.GetBuffer(), (aEvt.maText.Len() + 1) * sizeof(WCHAR) );
+ }
+
+ // just return the required size of buffer to reconvert.
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam )
+{
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ LPRECONVERTSTRING pReconvertString = (LPRECONVERTSTRING) lParam;
+ SalSurroundingTextRequestEvent aEvt;
+ aEvt.maText = UniString();
+ aEvt.mnStart = aEvt.mnEnd = 0;
+
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTREQUEST, (void*)&aEvt );
+
+ sal_uLong nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR);
+ sal_uLong nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen;
+
+ if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd )
+ {
+ SalSurroundingTextSelectionChangeEvent aSelEvt;
+ aSelEvt.mnStart = nTmpStart;
+ aSelEvt.mnEnd = nTmpEnd;
+
+ pFrame->CallCallback( SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE, (void*)&aSelEvt );
+ }
+
+ return TRUE;
+}
+
+#endif // WINVER >= 0x0500
+
+// -----------------------------------------------------------------------
+
+void SalTestMouseLeave()
+{
+ SalData* pSalData = GetSalData();
+
+ if ( pSalData->mhWantLeaveMsg && !::GetCapture() )
+ {
+ POINT aPt;
+ GetCursorPos( &aPt );
+ if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
+ ImplSendMessage( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+static int ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ,
+ LRESULT& rResult )
+{
+ POINT aPt;
+ POINT aScreenPt;
+ aScreenPt.x = (short)LOWORD( lParam );
+ aScreenPt.y = (short)HIWORD( lParam );
+ // Child-Fenster suchen, welches an der entsprechenden
+ // Position liegt
+ HWND hChildWnd;
+ HWND hWheelWnd = hWnd;
+ do
+ {
+ hChildWnd = hWheelWnd;
+ aPt = aScreenPt;
+ ScreenToClient( hChildWnd, &aPt );
+ hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT );
+ }
+ while ( hWheelWnd && (hWheelWnd != hChildWnd) );
+ if ( hWheelWnd && (hWheelWnd != hWnd) &&
+ (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
+ {
+ rResult = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+ static int bInWheelMsg = FALSE;
+ static int bInQueryEnd = FALSE;
+
+ // By WM_CRETAE we connect the frame with the window handle
+ if ( nMsg == WM_CREATE )
+ {
+ // Window-Instanz am Windowhandle speichern
+ // Can also be used for the W-Version, because the struct
+ // to access lpCreateParams is the same structure
+ CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam;
+ WinSalFrame* pFrame = (WinSalFrame*)pStruct->lpCreateParams;
+ if ( pFrame != 0 )
+ {
+ SetWindowPtr( hWnd, pFrame );
+ // HWND schon hier setzen, da schon auf den Instanzdaten
+ // gearbeitet werden kann, wenn Messages waehrend
+ // CreateWindow() gesendet werden
+ pFrame->mhWnd = hWnd;
+ pFrame->maSysData.hWnd = hWnd;
+ }
+ return 0;
+ }
+
+ ImplSVData* pSVData = ImplGetSVData();
+ // #i72707# TODO: the mbDeInit check will not be needed
+ // once all windows that are not properly closed on exit got fixed
+ if( pSVData->mbDeInit )
+ return 0;
+
+ if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg )
+ {
+ if (pSVData->mpIntroWindow)
+ pSVData->mpIntroWindow->Hide();
+
+ return 0;
+ }
+
+ bool bCheckTimers = false;
+
+ switch( nMsg )
+ {
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_NCMOUSEMOVE:
+ case SAL_MSG_MOUSELEAVE:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_NCLBUTTONDOWN:
+ case WM_NCMBUTTONDOWN:
+ case WM_NCRBUTTONDOWN:
+ ImplSalYieldMutexAcquireWithWait();
+ ImplCallClosePopupsHdl( hWnd ); // close popups...
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MOUSEACTIVATE:
+ if ( LOWORD( lParam ) == HTCLIENT )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ nRet = ImplHandleMouseActivateMsg( hWnd );
+ ImplSalYieldMutexRelease();
+ if ( nRet )
+ {
+ nRet = MA_NOACTIVATE;
+ rDef = FALSE;
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_DEADCHAR:
+ case WM_CHAR:
+ case WM_UNICHAR: // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_SYSCHAR:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MOUSEWHEEL:
+ // FALLTHROUGH intended
+ case WM_MOUSEHWHEEL:
+ // Gegen Rekursion absichern, falls wir vom IE oder dem externen
+ // Fenster die Message wieder zurueckbekommen
+ if ( !bInWheelMsg )
+ {
+ bInWheelMsg++;
+ rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam );
+ // Wenn wir die Message nicht ausgewertet haben, schauen wir
+ // noch einmal nach, ob dort ein geplugtes Fenster steht,
+ // welches wir dann benachrichtigen
+ if ( rDef )
+ rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
+ bInWheelMsg--;
+ }
+ break;
+
+ case WM_COMMAND:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleCommand( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_INITMENUPOPUP:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_MENUSELECT:
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_SYSCOMMAND:
+ ImplSalYieldMutexAcquireWithWait();
+ nRet = ImplHandleSysCommand( hWnd, wParam, lParam );
+ ImplSalYieldMutexRelease();
+ if ( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MENUCHAR:
+ nRet = ImplMenuChar( hWnd, wParam, lParam );
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MEASUREITEM:
+ nRet = ImplMeasureItem(hWnd, wParam, lParam);
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_DRAWITEM:
+ nRet = ImplDrawItem(hWnd, wParam, lParam);
+ if( nRet )
+ rDef = FALSE;
+ break;
+
+ case WM_MOVE:
+ case SAL_MSG_POSTMOVE:
+ ImplHandleMoveMsg( hWnd );
+ rDef = FALSE;
+ break;
+ case WM_SIZE:
+ ImplHandleSizeMsg( hWnd, wParam, lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTCALLSIZE:
+ ImplCallSizeHdl( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_GETMINMAXINFO:
+ if ( ImplHandleMinMax( hWnd, lParam ) )
+ rDef = FALSE;
+ break;
+
+ case WM_ERASEBKGND:
+ nRet = 1;
+ rDef = FALSE;
+ break;
+ case WM_PAINT:
+ bCheckTimers = ImplHandlePaintMsg( hWnd );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_POSTPAINT:
+ ImplHandlePaintMsg2( hWnd, (RECT*)wParam );
+ bCheckTimers = true;
+ rDef = FALSE;
+ break;
+
+ case SAL_MSG_FORCEPALETTE:
+ ImplHandleForcePalette( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_QUERYNEWPALETTE:
+ case SAL_MSG_POSTQUERYNEWPAL:
+ nRet = ImplHandlePalette( TRUE, hWnd, nMsg, wParam, lParam, rDef );
+ break;
+
+ case WM_ACTIVATE:
+ // Wenn wir aktiviert werden, dann wollen wir auch unsere
+ // Palette setzen. Wir machen dieses in Activate,
+ // damit andere externe Child-Fenster auch unsere Palette
+ // ueberschreiben koennen. So wird unsere jedenfalls nur einmal
+ // gesetzt und nicht immer rekursiv, da an allen anderen Stellen
+ // diese nur als Background-Palette gesetzt wird
+ if ( LOWORD( wParam ) != WA_INACTIVE )
+ ImplSendMessage( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
+ break;
+
+ case WM_ENABLE:
+ // #95133# a system dialog is opened/closed, using our app window as parent
+ {
+ WinSalFrame* pFrame = GetWindowPtr( hWnd );
+ Window *pWin = NULL;
+ if( pFrame )
+ pWin = pFrame->GetWindow();
+
+ if( !wParam )
+ {
+ ImplSVData* pSVData = ImplGetSVData();
+ pSVData->maAppData.mnModalMode++;
+
+ // #106431#, hide SplashScreen
+ if( pSVData->mpIntroWindow )
+ pSVData->mpIntroWindow->Hide();
+
+ if( pWin )
+ {
+ pWin->EnableInput( FALSE, TRUE, TRUE, NULL );
+ pWin->ImplIncModalCount(); // #106303# support frame based modal count
+ }
+ }
+ else
+ {
+ ImplGetSVData()->maAppData.mnModalMode--;
+ if( pWin )
+ {
+ pWin->EnableInput( TRUE, TRUE, TRUE, NULL );
+ pWin->ImplDecModalCount(); // #106303# support frame based modal count
+ }
+ }
+ }
+ break;
+
+ case WM_KILLFOCUS:
+ DestroyCaret();
+ case WM_SETFOCUS:
+ case SAL_MSG_POSTFOCUS:
+ ImplHandleFocusMsg( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_CLOSE:
+ ImplHandleCloseMsg( hWnd );
+ rDef = FALSE;
+ break;
+
+ case WM_QUERYENDSESSION:
+ if( !bInQueryEnd )
+ {
+ // handle queryendsession only once
+ bInQueryEnd = TRUE;
+ nRet = !ImplHandleShutDownMsg( hWnd );
+ rDef = FALSE;
+
+ // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown.
+ // This posted message was never processed and cause Windows XP to hang after log off
+ // if there are multiple sessions and the current session wasn't the first one started.
+ // So if shutdown is allowed we assume that a post message was done and retrieve all
+ // messages in the message queue and dispatch them before we return control to the system.
+
+ if ( nRet )
+ {
+ MSG msg;
+
+ while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
+ {
+ DispatchMessage( &msg );
+ }
+ }
+ }
+ else
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ ImplSalYieldMutexRelease();
+ rDef = TRUE;
+ }
+ break;
+
+ case WM_ENDSESSION:
+ if( !wParam )
+ bInQueryEnd = FALSE; // no shutdown: allow query again
+ nRet = FALSE;
+ rDef = FALSE;
+ break;
+
+ case WM_DISPLAYCHANGE:
+ case WM_SETTINGCHANGE:
+ case WM_DEVMODECHANGE:
+ case WM_FONTCHANGE:
+ case WM_SYSCOLORCHANGE:
+ case WM_TIMECHANGE:
+ ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam );
+ break;
+
+ case WM_THEMECHANGED:
+ GetSalData()->mbThemeChanged = TRUE;
+ break;
+
+ case SAL_MSG_USEREVENT:
+ ImplHandleUserEvent( hWnd, lParam );
+ rDef = FALSE;
+ break;
+
+ case SAL_MSG_CAPTUREMOUSE:
+ SetCapture( hWnd );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_RELEASEMOUSE:
+ if ( ::GetCapture() == hWnd )
+ ReleaseCapture();
+ rDef = FALSE;
+ break;
+ case SAL_MSG_TOTOP:
+ ImplSalToTop( hWnd, (sal_uInt16)wParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_SHOW:
+ ImplSalShow( hWnd, (sal_Bool)wParam, (sal_Bool)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_SETINPUTCONTEXT:
+ ImplSalFrameSetInputContext( hWnd, (const SalInputContext*)(void*)lParam );
+ rDef = FALSE;
+ break;
+ case SAL_MSG_ENDEXTTEXTINPUT:
+ ImplSalFrameEndExtTextInput( hWnd, (sal_uInt16)(sal_uLong)(void*)wParam );
+ rDef = FALSE;
+ break;
+
+ case WM_INPUTLANGCHANGE:
+ ImplHandleInputLangChange( hWnd, wParam, lParam );
+ break;
+
+ case WM_IME_CHAR:
+ // #103487#, some IMEs (eg, those that do not work onspot)
+ // may send WM_IME_CHAR instead of WM_IME_COMPOSITION
+ // we just handle it like a WM_CHAR message - seems to work fine
+ ImplSalYieldMutexAcquireWithWait();
+ rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet );
+ ImplSalYieldMutexRelease();
+ break;
+
+ case WM_IME_STARTCOMPOSITION:
+ rDef = ImplHandleIMEStartComposition( hWnd );
+ break;
+
+ case WM_IME_COMPOSITION:
+ rDef = ImplHandleIMEComposition( hWnd, lParam );
+ break;
+
+ case WM_IME_ENDCOMPOSITION:
+ rDef = ImplHandleIMEEndComposition( hWnd );
+ break;
+
+ case WM_IME_NOTIFY:
+ ImplHandleIMENotify( hWnd, wParam );
+ break;
+ case WM_APPCOMMAND:
+ if( ImplHandleAppCommand( hWnd, lParam ) )
+ {
+ rDef = false;
+ nRet = 1;
+ }
+ break;
+#if WINVER >= 0x0500
+ case WM_IME_REQUEST:
+ if ( PtrToInt( wParam ) == IMR_RECONVERTSTRING )
+ {
+ nRet = ImplHandleIMEReconvertString( hWnd, lParam );
+ rDef = FALSE;
+ }
+ else if( PtrToInt( wParam ) == IMR_CONFIRMRECONVERTSTRING )
+ {
+ nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam );
+ rDef = FALSE;
+ }
+ break;
+#endif // WINVER >= 0x0500
+ }
+
+ // WheelMouse-Message abfangen
+ if ( rDef && (nMsg == aSalShlData.mnWheelMsgId) && aSalShlData.mnWheelMsgId )
+ {
+ // Gegen Rekursion absichern, falls wir vom IE oder dem externen
+ // Fenster die Message wieder zurueckbekommen
+ if ( !bInWheelMsg )
+ {
+ bInWheelMsg++;
+ // Zuerst wollen wir die Message dispatchen und dann darf auch
+ // das SystemWindow drankommen
+ WORD nKeyState = 0;
+ if ( GetKeyState( VK_SHIFT ) & 0x8000 )
+ nKeyState |= MK_SHIFT;
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ nKeyState |= MK_CONTROL;
+ // Mutex handling is inside from this call
+ rDef = !ImplHandleWheelMsg( hWnd,
+ WM_MOUSEWHEEL,
+ MAKEWPARAM( nKeyState, (WORD)wParam ),
+ lParam );
+ if ( rDef )
+ {
+ HWND hWheelWnd = ::GetFocus();
+ if ( hWheelWnd && (hWheelWnd != hWnd) )
+ {
+ nRet = ImplSendMessage( hWheelWnd, nMsg, wParam, lParam );
+ rDef = FALSE;
+ }
+ else
+ rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
+ }
+ bInWheelMsg--;
+ }
+ }
+
+ if( bCheckTimers )
+ {
+ SalData* pSalData = GetSalData();
+ if( pSalData->mnNextTimerTime )
+ {
+ DWORD nCurTime = GetTickCount();
+ if( pSalData->mnNextTimerTime < nCurTime )
+ {
+ MSG aMsg;
+ if( ! ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE | PM_NOYIELD ) )
+ ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_POSTTIMER, 0, nCurTime );
+ }
+ }
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalFrameWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = 0;
+#ifdef __MINGW32__
+ jmp_buf jmpbuf;
+ __SEHandler han;
+ if (__builtin_setjmp(jmpbuf) == 0)
+ {
+ han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
+#else
+ __try
+ {
+#endif
+ nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ }
+#ifdef __MINGW32__
+ han.Reset();
+#else
+ __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+#endif
+
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult )
+{
+ // handle all messages concerning all frames so they get processed only once
+ // Must work for Unicode and none Unicode
+ sal_Bool bResult = FALSE;
+ if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
+ {
+ int bDef = TRUE;
+ rlResult = ImplHandlePalette( FALSE, hWnd, nMsg, wParam, lParam, bDef );
+ bResult = (bDef != 0);
+ }
+ else if( nMsg == WM_DISPLAYCHANGE )
+ {
+ WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
+ if( pSys )
+ pSys->clearMonitors();
+ bResult = (pSys != NULL);
+ }
+ return bResult;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplWriteLastError( DWORD lastError, const char *szApiCall )
+{
+ static int first=1;
+ // if VCL_LOGFILE_ENABLED is set, Win32 API error messages can be written
+ // to %TMP%/vcl.log or %TEMP%/vcl.log
+ static char *logEnabled = getenv("VCL_LOGFILE_ENABLED");
+ if( logEnabled )
+ {
+ sal_Bool bSuccess = FALSE;
+ static char *szTmp = getenv("TMP");
+ if( !szTmp || !*szTmp )
+ szTmp = getenv("TEMP");
+ if( szTmp && *szTmp )
+ {
+ char fname[5000];
+ strcpy( fname, szTmp );
+ if( fname[strlen(fname) - 1] != '\\' )
+ strcat( fname, "\\");
+ strcat( fname, "vcl.log" );
+ FILE *fp = fopen( fname, "a" ); // always append
+ if( fp )
+ {
+ if( first )
+ {
+ first = 0;
+ fprintf( fp, "Process ID: %d (0x%x)\n", GetCurrentProcessId(), GetCurrentProcessId() );
+ }
+ time_t aclock;
+ time( &aclock ); // Get time in seconds
+ struct tm *newtime = localtime( &aclock ); // Convert time to struct tm form
+ fprintf( fp, asctime( newtime ) ); // print time stamp
+
+ fprintf( fp, "%s returned %u (0x%x)\n", szApiCall, lastError, lastError );
+ bSuccess = TRUE; // may be FormatMessage fails but we wrote at least the error code
+
+ LPVOID lpMsgBuf;
+ if (FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ lastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPSTR) &lpMsgBuf,
+ 0,
+ NULL ))
+ {
+ fprintf( fp, " %s\n", (LPSTR)lpMsgBuf );
+ LocalFree( lpMsgBuf );
+ }
+
+ fclose( fp );
+ }
+ }
+ return bSuccess;
+ }
+ else
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/vcl/win/source/window/salmenu.cxx b/vcl/win/source/window/salmenu.cxx
new file mode 100755
index 000000000000..ce7c6064f790
--- /dev/null
+++ b/vcl/win/source/window/salmenu.cxx
@@ -0,0 +1,414 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <tools/svwin.h>
+
+#include <vcl/menu.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salframe.h>
+#include <win/salmenu.h>
+
+#include <impbmp.hxx>
+#include <salgdi.hxx>
+
+// uncomment the following line to have ownerdrawn menues, ie, with bitmaps
+// however, this is incompatible with OLE inplace editing
+// so it is not activated by default
+//#define OWNERDRAW
+
+static DWORD myerr=0;
+
+// =======================================================================
+
+sal_Bool SalData::IsKnownMenuHandle( HMENU hMenu )
+{
+ if( mhMenuSet.find( hMenu ) == mhMenuSet.end() )
+ return FALSE;
+ else
+ return TRUE;
+}
+
+// =======================================================================
+
+// WinSalInst factory methods
+
+SalMenu* WinSalInstance::CreateMenu( sal_Bool bMenuBar, Menu* )
+{
+ WinSalMenu *pSalMenu = new WinSalMenu();
+
+ pSalMenu->mbMenuBar = bMenuBar;
+ pSalMenu->mhWnd = NULL;
+ if( bMenuBar )
+ pSalMenu->mhMenu = ::CreateMenu();
+ else
+ pSalMenu->mhMenu = ::CreatePopupMenu();
+
+ if( pSalMenu->mhMenu )
+ GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu );
+
+ return pSalMenu;
+}
+
+void WinSalInstance::DestroyMenu( SalMenu* pSalMenu )
+{
+ delete pSalMenu;
+}
+
+
+SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData )
+{
+ if( !pItemData )
+ return NULL;
+
+ WinSalMenuItem *pSalMenuItem = new WinSalMenuItem();
+ memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) );
+ pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW );
+
+ if( pItemData->eType == MENUITEM_SEPARATOR )
+ {
+ // separator
+ pSalMenuItem->mInfo.fMask = MIIM_TYPE;
+ pSalMenuItem->mInfo.fType = MFT_SEPARATOR;
+ }
+ else
+ {
+ // item
+ pSalMenuItem->mText = pItemData->aText;
+ pSalMenuItem->mpMenu = pItemData->pMenu;
+ pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap();
+ pSalMenuItem->mnId = pItemData->nId;
+
+ // 'translate' mnemonics
+ pSalMenuItem->mText.SearchAndReplace( '~', '&' );
+
+ pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
+ pSalMenuItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pItemData->pMenu && !pItemData->pMenu->IsMenuBar() )
+ pSalMenuItem->mInfo.fType |= MFT_OWNERDRAW;
+ pSalMenuItem->mInfo.fState = MFS_ENABLED;
+#endif
+ pSalMenuItem->mInfo.dwTypeData = (LPWSTR) pSalMenuItem->mText.GetBuffer();
+ pSalMenuItem->mInfo.cch = pSalMenuItem->mText.Len();
+
+ pSalMenuItem->mInfo.wID = pItemData->nId;
+ pSalMenuItem->mInfo.dwItemData = (ULONG_PTR) pSalMenuItem; // user data
+ }
+
+ return pSalMenuItem;
+}
+
+void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem )
+{
+ delete pSalMenuItem;
+}
+
+
+// =======================================================================
+
+static void ImplDrawMenuBar( SalMenu *pMenu )
+{
+ if( pMenu->VisibleMenuBar() )
+ {
+ // redrawing the menubar all the time actually seems to be unnecessary (it just flickers)
+ /*
+ WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu );
+ if( pMenuBar && pMenuBar->mhWnd )
+ ::DrawMenuBar( pMenuBar->mhWnd );
+ */
+ }
+}
+
+// =======================================================================
+
+
+/*
+ * WinSalMenu
+ */
+
+WinSalMenu::WinSalMenu()
+{
+ mhMenu = NULL;
+ mbMenuBar = FALSE;
+ mhWnd = NULL;
+ mpParentMenu = NULL;
+}
+
+WinSalMenu::~WinSalMenu()
+{
+ // only required if not associated to a window...
+ GetSalData()->mhMenuSet.erase( mhMenu );
+ ::DestroyMenu( mhMenu );
+}
+
+sal_Bool WinSalMenu::VisibleMenuBar()
+{
+ // The Win32 implementation never shows a native
+ // menubar. Thus, native menues are only visible
+ // when the menu is merged with an OLE container.
+ // The reason are missing tooltips, ownerdraw
+ // issues and accessibility which are better supported
+ // by VCL menues.
+ // Nevertheless, the native menues are always created
+ // and the application will properly react to all native
+ // menu messages.
+
+ return FALSE;
+}
+
+void WinSalMenu::SetFrame( const SalFrame *pFrame )
+{
+ if( pFrame )
+ mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd;
+ else
+ mhWnd = NULL;
+}
+
+void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ if( nPos == MENU_APPEND )
+ {
+ nPos = ::GetMenuItemCount( mhMenu );
+ if( nPos == -1 )
+ return;
+ }
+
+ if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ {
+ pWItem->mpSalMenu = this;
+ ImplDrawMenuBar( this );
+ }
+ }
+}
+
+void WinSalMenu::RemoveItem( unsigned nPos )
+{
+ int num = ::GetMenuItemCount( mhMenu );
+ if( num != -1 && nPos < (unsigned)num )
+ {
+ WinSalMenuItem *pSalMenuItem = NULL;
+
+ MENUITEMINFOW mi;
+ memset( &mi, 0, sizeof(mi) );
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) )
+ myerr = GetLastError();
+ else
+ pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
+
+ if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = NULL;
+ ImplDrawMenuBar( this );
+ }
+ }
+}
+
+void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId )
+{
+ if( !pSalMenu )
+ return;
+
+ WinSalMenuItem *pSalMenuItem = NULL;
+
+ MENUITEMINFOW mi;
+ memset( &mi, 0, sizeof(mi) );
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_DATA;
+ if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) )
+ myerr = GetLastError();
+ else
+ pSalMenuItem = (WinSalMenuItem *) mi.dwItemData;
+
+ if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) )
+ myerr = GetLastError();
+ else
+ {
+ if( pSalMenuItem )
+ pSalMenuItem->mpSalMenu = NULL;
+ ImplDrawMenuBar( pSalMenu );
+ }
+}
+
+void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu);
+ if( pWMenuItem->mInfo.hSubMenu )
+ {
+ GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu );
+ ::DestroyMenu( pWMenuItem->mInfo.hSubMenu );
+ }
+
+ pWMenuItem->mInfo.fMask |= MIIM_SUBMENU;
+ if( !pSubMenu )
+ pWMenuItem->mInfo.hSubMenu = NULL;
+ else
+ {
+ pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu;
+ pWSubMenu->mpParentMenu = this;
+ }
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) )
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck )
+{
+ if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable )
+{
+ if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) )
+ ImplDrawMenuBar( this );
+}
+
+void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ if( !!rImage )
+ pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap();
+ else
+ pWItem->maBitmap = Bitmap();
+ }
+}
+
+void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ pWItem->mText = rText;
+ // 'translate' mnemonics
+ pWItem->mText.SearchAndReplace( '~', '&' );
+ pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
+ pWItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pWItem->mpMenu && !((Menu*) pWItem->mpMenu)->IsMenuBar() )
+ pWItem->mInfo.fType |= MFT_OWNERDRAW;
+#endif
+
+ // combine text and accelerator text
+ XubString aStr( pWItem->mText );
+ if( pWItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii("\t");
+ aStr.Append( pWItem->mAccelText );
+ }
+ pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
+ pWItem->mInfo.cch = aStr.Len();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode&, const XubString& rKeyName )
+{
+ if( pSalMenuItem )
+ {
+ WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem);
+ pWItem->mAccelText = rKeyName;
+ pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA;
+ pWItem->mInfo.fType = MFT_STRING;
+#ifdef OWNERDRAW
+ if( pWItem->mpMenu && !((Menu*)pWItem->mpMenu)->IsMenuBar() )
+ pWItem->mInfo.fType |= MFT_OWNERDRAW;
+#endif
+ // combine text and accelerator text
+ XubString aStr( pWItem->mText );
+ if( pWItem->mAccelText.Len() )
+ {
+ aStr.AppendAscii("\t");
+ aStr.Append( pWItem->mAccelText );
+ }
+ pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer();
+ pWItem->mInfo.cch = aStr.Len();
+
+ if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo ))
+ myerr = GetLastError();
+ else
+ ImplDrawMenuBar( this );
+ }
+}
+
+void WinSalMenu::GetSystemMenuData( SystemMenuData* pData )
+{
+ if( pData )
+ pData->hMenu = mhMenu;
+}
+
+// =======================================================================
+
+/*
+ * SalMenuItem
+ */
+
+
+WinSalMenuItem::WinSalMenuItem()
+{
+ memset( &mInfo, 0, sizeof( MENUITEMINFOW ) );
+ mpMenu = NULL;
+ mnId = 0xFFFF;
+ mpSalMenu = NULL;
+}
+
+WinSalMenuItem::~WinSalMenuItem()
+{
+ if( mpSalMenu )
+ ImplRemoveItemById( mpSalMenu, mnId );
+}
+
+// -------------------------------------------------------------------
+
diff --git a/vcl/win/source/window/salobj.cxx b/vcl/win/source/window/salobj.cxx
new file mode 100755
index 000000000000..51712f07e709
--- /dev/null
+++ b/vcl/win/source/window/salobj.cxx
@@ -0,0 +1,878 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <string.h>
+
+#include <tools/debug.hxx>
+#include <tools/svwin.h>
+
+#include <vcl/svapp.hxx>
+
+#include <win/wincomp.hxx>
+#include <win/saldata.hxx>
+#include <win/salinst.h>
+#include <win/salframe.h>
+#include <win/salobj.h>
+
+// =======================================================================
+
+static sal_Bool ImplIsSysWindowOrChild( HWND hWndParent, HWND hWndChild )
+{
+ if ( hWndParent == hWndChild )
+ return TRUE;
+
+ HWND hTempWnd = ::GetParent( hWndChild );
+ while ( hTempWnd )
+ {
+ // Ab nicht Child-Fenstern hoeren wir auf zu suchen
+ if ( !(GetWindowStyle( hTempWnd ) & WS_CHILD) )
+ return FALSE;
+ if ( hTempWnd == hWndParent )
+ return TRUE;
+ hTempWnd = ::GetParent( hTempWnd );
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalObject* ImplFindSalObject( HWND hWndChild )
+{
+ SalData* pSalData = GetSalData();
+ WinSalObject* pObject = pSalData->mpFirstObject;
+ while ( pObject )
+ {
+ if ( ImplIsSysWindowOrChild( pObject->mhWndChild, hWndChild ) )
+ return pObject;
+
+ pObject = pObject->mpNextObject;
+ }
+
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalFrame* ImplFindSalObjectFrame( HWND hWnd )
+{
+ WinSalFrame* pFrame = NULL;
+ WinSalObject* pObject = ImplFindSalObject( hWnd );
+ if ( pObject )
+ {
+ // Dazugehoerenden Frame suchen
+ HWND hWnd = ::GetParent( pObject->mhWnd );
+ pFrame = GetSalData()->mpFirstFrame;
+ while ( pFrame )
+ {
+ if ( pFrame->mhWnd == hWnd )
+ break;
+
+ pFrame = pFrame->mpNextFrame;
+ }
+ }
+
+ return pFrame;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplInterceptChildWindowKeyDown( MSG& rMsg )
+{
+ sal_Bool bResult = sal_False;
+ if ( rMsg.message == WM_KEYDOWN )
+ {
+ wchar_t pClassName[10];
+ sal_Int32 nLen = GetClassNameW( rMsg.hwnd, pClassName, 10 );
+ if ( !( nLen == 9 && wcsncmp( pClassName, SAL_OBJECT_CLASSNAMEW, nLen ) == 0 ) )
+ {
+ // look for the first SalObject in the parent hierarchy
+ HWND hWin = rMsg.hwnd;
+ HWND hLastOLEWindow = hWin;
+ WinSalObject* pSalObj = NULL;
+ do
+ {
+ hLastOLEWindow = hWin;
+ hWin = ::GetParent( hWin );
+ if ( hWin )
+ {
+ nLen = GetClassNameW( hWin, pClassName, 10 );
+ if ( nLen == 9 && wcsncmp( pClassName, SAL_OBJECT_CLASSNAMEW, nLen ) == 0 )
+ pSalObj = GetSalObjWindowPtr( hWin );
+ }
+ } while( hWin && !pSalObj );
+
+ if ( pSalObj && pSalObj->mbInterceptChildWindowKeyDown && pSalObj->maSysData.hWnd )
+ {
+ bResult = ( 1 == ImplSendMessage( pSalObj->maSysData.hWnd, rMsg.message, rMsg.wParam, rMsg.lParam ) );
+ }
+ }
+ }
+
+ return bResult;
+}
+
+// -----------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalSysMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+
+ if ( (nCode >= 0) && lParam )
+ {
+ CWPSTRUCT* pData = (CWPSTRUCT*)lParam;
+ if ( (pData->message != WM_KEYDOWN) &&
+ (pData->message != WM_KEYUP) )
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ // Testen, ob wir Daten fuer ein SalObject-Fenster behandeln
+ // muessen
+ WinSalObject* pObject;
+ if ( pData->message == WM_SETFOCUS )
+ {
+ pObject = ImplFindSalObject( pData->hwnd );
+ if ( pObject )
+ {
+ pObject->mhLastFocusWnd = pData->hwnd;
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ }
+ }
+ else if ( pData->message == WM_KILLFOCUS )
+ {
+ pObject = ImplFindSalObject( pData->hwnd );
+ if ( pObject && !ImplFindSalObject( (HWND)pData->wParam ) )
+ {
+ // LoseFocus nur rufen, wenn wirklich kein ChildFenster
+ // den Focus bekommt
+ if ( !pData->wParam || !ImplFindSalObject( (HWND)pData->wParam ) )
+ {
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ }
+ else
+ pObject->mhLastFocusWnd = (HWND)pData->wParam;
+ }
+ }
+ }
+
+ return CallNextHookEx( pSalData->mhSalObjMsgHook, nCode, wParam, lParam );
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool ImplSalPreDispatchMsg( MSG* pMsg )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+ WinSalObject* pObject;
+
+ if ( (pMsg->message == WM_LBUTTONDOWN) ||
+ (pMsg->message == WM_RBUTTONDOWN) ||
+ (pMsg->message == WM_MBUTTONDOWN) )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject && !pObject->IsMouseTransparent() )
+ ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ ImplSalYieldMutexRelease();
+ }
+
+ if ( (pMsg->message == WM_KEYDOWN) ||
+ (pMsg->message == WM_KEYUP) )
+ {
+ // KeyEvents wollen wir nach Moeglichkeit auch abarbeiten,
+ // wenn das Control diese nicht selber auswertet
+ // SysKeys werden als WM_SYSCOMMAND verarbeitet
+ // Char-Events verarbeiten wir nicht, da wir nur
+ // Accelerator relevante Keys verarbeiten wollen
+ sal_Bool bWantedKeyCode = FALSE;
+ // A-Z, 0-9 nur in Verbindung mit Control-Taste
+ if ( ((pMsg->wParam >= 65) && (pMsg->wParam <= 90)) ||
+ ((pMsg->wParam >= 48) && (pMsg->wParam <= 57)) )
+ {
+ if ( GetKeyState( VK_CONTROL ) & 0x8000 )
+ bWantedKeyCode = TRUE;
+ }
+ else if ( ((pMsg->wParam >= VK_F1) && (pMsg->wParam <= VK_F24)) ||
+ ((pMsg->wParam >= VK_SPACE) && (pMsg->wParam <= VK_HELP)) ||
+ (pMsg->wParam == VK_BACK) || (pMsg->wParam == VK_TAB) ||
+ (pMsg->wParam == VK_CLEAR) || (pMsg->wParam == VK_RETURN) ||
+ (pMsg->wParam == VK_ESCAPE) )
+ bWantedKeyCode = TRUE;
+ if ( bWantedKeyCode )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject )
+ pSalData->mnSalObjWantKeyEvt = pMsg->wParam;
+ ImplSalYieldMutexRelease();
+ }
+ }
+ // Hier WM_SYSCHAR abfangen, um mit Alt+Taste evtl. Menu zu aktivieren
+ else if ( pMsg->message == WM_SYSCHAR )
+ {
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ sal_uInt16 nKeyCode = LOWORD( pMsg->wParam );
+ // Nur 0-9 und A-Z
+ if ( ((nKeyCode >= 48) && (nKeyCode <= 57)) ||
+ ((nKeyCode >= 65) && (nKeyCode <= 90)) ||
+ ((nKeyCode >= 97) && (nKeyCode <= 122)) )
+ {
+ sal_Bool bRet = FALSE;
+ ImplSalYieldMutexAcquireWithWait();
+ pObject = ImplFindSalObject( pMsg->hwnd );
+ if ( pObject )
+ {
+ if ( pMsg->hwnd == ::GetFocus() )
+ {
+ WinSalFrame* pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
+ if ( pFrame )
+ {
+ if ( ImplHandleSalObjSysCharMsg( pFrame->mhWnd, pMsg->wParam, pMsg->lParam ) )
+ bRet = TRUE;
+ }
+ }
+ }
+ ImplSalYieldMutexRelease();
+ if ( bRet )
+ return TRUE;
+ }
+ }
+ else
+ pSalData->mnSalObjWantKeyEvt = 0;
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT /* nDispatchResult */ )
+{
+ // Used for Unicode and none Unicode
+ SalData* pSalData = GetSalData();
+ WinSalFrame* pFrame;
+
+ if ( (pMsg->message == WM_KEYDOWN) || (pMsg->message == WM_KEYUP) )
+ {
+ if ( pSalData->mnSalObjWantKeyEvt == pMsg->wParam )
+ {
+ pSalData->mnSalObjWantKeyEvt = 0;
+ if ( pMsg->hwnd == ::GetFocus() )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
+ if ( pFrame )
+ ImplHandleSalObjKeyMsg( pFrame->mhWnd, pMsg->message, pMsg->wParam, pMsg->lParam );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ }
+
+ pSalData->mnSalObjWantKeyEvt = 0;
+}
+
+// =======================================================================
+
+LRESULT CALLBACK SalSysObjWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ WinSalObject* pSysObj;
+ LRESULT nRet = 0;
+
+ switch( nMsg )
+ {
+ case WM_ERASEBKGND:
+ nRet = 1;
+ rDef = FALSE;
+ break;
+ case WM_PAINT:
+ {
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ EndPaint( hWnd, &aPs );
+ rDef = FALSE;
+ }
+ break;
+
+ case WM_PARENTNOTIFY:
+ {
+ UINT nNotifyMsg = LOWORD( wParam );
+ if ( (nNotifyMsg == WM_LBUTTONDOWN) ||
+ (nNotifyMsg == WM_RBUTTONDOWN) ||
+ (nNotifyMsg == WM_MBUTTONDOWN) )
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ if ( pSysObj && !pSysObj->IsMouseTransparent() )
+ pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ }
+ break;
+
+ case WM_MOUSEACTIVATE:
+ {
+ ImplSalYieldMutexAcquireWithWait();
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ if ( pSysObj && !pSysObj->IsMouseTransparent() )
+ ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ break;
+
+ case SALOBJ_MSG_TOTOP:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
+ ImplSalYieldMutexRelease();
+ rDef = FALSE;
+ }
+ else
+ ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
+ break;
+
+ case SALOBJ_MSG_POSTFOCUS:
+ if ( ImplSalYieldMutexTryToAcquire() )
+ {
+ pSysObj = GetSalObjWindowPtr( hWnd );
+ HWND hFocusWnd = ::GetFocus();
+ sal_uInt16 nEvent;
+ if ( hFocusWnd && ImplIsSysWindowOrChild( hWnd, hFocusWnd ) )
+ nEvent = SALOBJ_EVENT_GETFOCUS;
+ else
+ nEvent = SALOBJ_EVENT_LOSEFOCUS;
+ pSysObj->CallCallback( nEvent, 0 );
+ ImplSalYieldMutexRelease();
+ }
+ else
+ ImplPostMessage( hWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
+ rDef = FALSE;
+ break;
+
+ case WM_SIZE:
+ {
+ HWND hWndChild = GetWindow( hWnd, GW_CHILD );
+ if ( hWndChild )
+ {
+ SetWindowPos( hWndChild,
+ 0, 0, 0, (int)LOWORD( lParam ), (int)HIWORD( lParam ),
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ }
+ }
+ rDef = FALSE;
+ break;
+
+ case WM_CREATE:
+ {
+ // Window-Instanz am Windowhandle speichern
+ // Can also be used for the W-Version, because the struct
+ // to access lpCreateParams is the same structure
+ CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam;
+ pSysObj = (WinSalObject*)pStruct->lpCreateParams;
+ SetSalObjWindowPtr( hWnd, pSysObj );
+ // HWND schon hier setzen, da schon auf den Instanzdaten
+ // gearbeitet werden kann, wenn Messages waehrend
+ // CreateWindow() gesendet werden
+ pSysObj->mhWnd = hWnd;
+ rDef = FALSE;
+ }
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// -----------------------------------------------------------------------
+
+LRESULT CALLBACK SalSysObjChildWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
+{
+ LRESULT nRet = 0;
+
+ switch( nMsg )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ case WM_ERASEBKGND:
+ {
+ WinSalObject* pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );
+
+ if( pSysObj && !pSysObj->IsEraseBackgroundEnabled() )
+ {
+ // do not erase background
+ nRet = 1;
+ rDef = FALSE;
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT aPs;
+ BeginPaint( hWnd, &aPs );
+ EndPaint( hWnd, &aPs );
+ rDef = FALSE;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ {
+ WinSalObject* pSysObj;
+ pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );
+
+ if( pSysObj && pSysObj->IsMouseTransparent() )
+ {
+ // forward mouse events to parent frame
+ HWND hWndParent = ::GetParent( pSysObj->mhWnd );
+
+ // transform coordinates
+ POINT pt;
+ pt.x = (long) LOWORD( lParam );
+ pt.y = (long) HIWORD( lParam );
+ MapWindowPoints( hWnd, hWndParent, &pt, 1 );
+ lParam = MAKELPARAM( (WORD) pt.x, (WORD) pt.y );
+
+ nRet = ImplSendMessage( hWndParent, nMsg, wParam, lParam );
+ rDef = FALSE;
+ }
+ }
+ break;
+ }
+
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjChildWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+LRESULT CALLBACK SalSysObjChildWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
+{
+ int bDef = TRUE;
+ LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
+ if ( bDef )
+ nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
+ return nRet;
+}
+
+// =======================================================================
+
+SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent )
+{
+ SalData* pSalData = GetSalData();
+
+ // Hook installieren, wenn es das erste SalObject ist
+ if ( !pSalData->mpFirstObject )
+ {
+ pSalData->mhSalObjMsgHook = SetWindowsHookExW( WH_CALLWNDPROC,
+ SalSysMsgProc,
+ pSalData->mhInst,
+ pSalData->mnAppThreadId );
+ }
+
+ if ( !pSalData->mbObjClassInit )
+ {
+ // #95301# shockwave plugin has bug; expects ASCII functions to be used
+ if ( false )//aSalShlData.mbWNT )
+ {
+ WNDCLASSEXW aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalSysObjWndProcW;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW );
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEW;
+ if ( RegisterClassExW( &aWndClassEx ) )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ aWndClassEx.lpfnWndProc = SalSysObjChildWndProcW;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEW;
+ if ( RegisterClassExW( &aWndClassEx ) )
+ pSalData->mbObjClassInit = TRUE;
+ }
+ }
+ else
+ {
+ WNDCLASSEXA aWndClassEx;
+ aWndClassEx.cbSize = sizeof( aWndClassEx );
+ aWndClassEx.style = 0;
+ aWndClassEx.lpfnWndProc = SalSysObjWndProcA;
+ aWndClassEx.cbClsExtra = 0;
+ aWndClassEx.cbWndExtra = SAL_OBJECT_WNDEXTRA;
+ aWndClassEx.hInstance = pSalData->mhInst;
+ aWndClassEx.hIcon = 0;
+ aWndClassEx.hIconSm = 0;
+ aWndClassEx.hCursor = LoadCursor( 0, IDC_ARROW );
+ aWndClassEx.hbrBackground = 0;
+ aWndClassEx.lpszMenuName = 0;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CLASSNAMEA;
+ if ( RegisterClassExA( &aWndClassEx ) )
+ {
+ // Wegen PlugIn's loeschen wir erstmal den Hintergrund
+ aWndClassEx.cbWndExtra = 0;
+ aWndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ aWndClassEx.lpfnWndProc = SalSysObjChildWndProcA;
+ aWndClassEx.lpszClassName = SAL_OBJECT_CHILDCLASSNAMEA;
+ if ( RegisterClassExA( &aWndClassEx ) )
+ pSalData->mbObjClassInit = TRUE;
+ }
+ }
+ }
+
+ if ( pSalData->mbObjClassInit )
+ {
+ WinSalObject* pObject = new WinSalObject;
+
+ // #135235# Clip siblings of this
+ // SystemChildWindow. Otherwise, DXCanvas (using a hidden
+ // SystemChildWindow) clobbers applets/plugins during
+ // animations .
+ HWND hWnd = CreateWindowExA( 0, SAL_OBJECT_CLASSNAMEA, "",
+ WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0,
+ pParent->mhWnd, 0,
+ pInst->mhInst, (void*)pObject );
+
+ HWND hWndChild = 0;
+ if ( hWnd )
+ {
+ // #135235# Explicitely stack SystemChildWindows in
+ // the order they're created - since there's no notion
+ // of zorder.
+ SetWindowPos(hWnd,HWND_TOP,0,0,0,0,
+ SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE);
+ hWndChild = CreateWindowExA( 0, SAL_OBJECT_CHILDCLASSNAMEA, "",
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
+ 0, 0, 0, 0,
+ hWnd, 0,
+ pInst->mhInst, NULL );
+ }
+
+ if ( !hWndChild )
+ {
+ delete pObject;
+ return NULL;
+ }
+
+ if ( hWnd )
+ {
+ pObject->mhWnd = hWnd;
+ pObject->mhWndChild = hWndChild;
+ pObject->maSysData.hWnd = hWndChild;
+ return pObject;
+ }
+ }
+
+ return NULL;
+}
+
+// =======================================================================
+
+WinSalObject::WinSalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ mhWnd = 0;
+ mhWndChild = 0;
+ mhLastFocusWnd = 0;
+ maSysData.nSize = sizeof( SystemEnvData );
+ mpStdClipRgnData = NULL;
+ mbInterceptChildWindowKeyDown = sal_False;
+
+ // Insert object in objectlist
+ mpNextObject = pSalData->mpFirstObject;
+ pSalData->mpFirstObject = this;
+}
+
+// -----------------------------------------------------------------------
+
+WinSalObject::~WinSalObject()
+{
+ SalData* pSalData = GetSalData();
+
+ // remove frame from framelist
+ if ( this == pSalData->mpFirstObject )
+ {
+ pSalData->mpFirstObject = mpNextObject;
+
+ // Wenn letztes SalObject, dann Hook wieder entfernen
+ if ( !pSalData->mpFirstObject )
+ UnhookWindowsHookEx( pSalData->mhSalObjMsgHook );
+ }
+ else
+ {
+ WinSalObject* pTempObject = pSalData->mpFirstObject;
+ while ( pTempObject->mpNextObject != this )
+ pTempObject = pTempObject->mpNextObject;
+
+ pTempObject->mpNextObject = mpNextObject;
+ }
+
+ // Cache-Daten zerstoeren
+ if ( mpStdClipRgnData )
+ delete mpStdClipRgnData;
+
+ HWND hWndParent = ::GetParent( mhWnd );
+
+ if ( mhWndChild )
+ DestroyWindow( mhWndChild );
+ if ( mhWnd )
+ DestroyWindow( mhWnd );
+
+ // Palette wieder zuruecksetzen, wenn kein externes Child-Fenster
+ // mehr vorhanden ist, da diese unsere Palette ueberschrieben haben
+ // koennen
+ if ( hWndParent &&
+ ::GetActiveWindow() == hWndParent &&
+ !GetWindow( hWndParent, GW_CHILD ) )
+ ImplSendMessage( hWndParent, SAL_MSG_FORCEPALETTE, 0, 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::ResetClipRegion()
+{
+ SetWindowRgn( mhWnd, 0, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt16 WinSalObject::GetClipRegionType()
+{
+ return SAL_OBJECT_CLIP_INCLUDERECTS;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::BeginSetClipRegion( sal_uLong nRectCount )
+{
+ sal_uLong nRectBufSize = sizeof(RECT)*nRectCount;
+ if ( nRectCount < 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 = nRectCount;
+ mpClipRgnData->rdh.nRgnSize = nRectBufSize;
+ SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
+ mpNextClipRect = (RECT*)(&(mpClipRgnData->Buffer));
+ mbFirstClipRect = TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
+{
+ RECT* pRect = mpNextClipRect;
+ RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
+ long nRight = nX + nWidth;
+ long nBottom = nY + nHeight;
+
+ if ( mbFirstClipRect )
+ {
+ pBoundRect->left = nX;
+ pBoundRect->top = nY;
+ pBoundRect->right = nRight;
+ pBoundRect->bottom = nBottom;
+ mbFirstClipRect = FALSE;
+ }
+ else
+ {
+ if ( nX < pBoundRect->left )
+ pBoundRect->left = (int)nX;
+
+ if ( nY < pBoundRect->top )
+ pBoundRect->top = (int)nY;
+
+ if ( nRight > pBoundRect->right )
+ pBoundRect->right = (int)nRight;
+
+ if ( nBottom > pBoundRect->bottom )
+ pBoundRect->bottom = (int)nBottom;
+ }
+
+ pRect->left = (int)nX;
+ pRect->top = (int)nY;
+ pRect->right = (int)nRight;
+ pRect->bottom = (int)nBottom;
+ mpNextClipRect++;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::EndSetClipRegion()
+{
+ HRGN hRegion;
+
+ // Aus den Region-Daten muessen wir jetzt eine ClipRegion erzeugen
+ if ( mpClipRgnData->rdh.nCount == 1 )
+ {
+ RECT* pRect = &(mpClipRgnData->rdh.rcBound);
+ hRegion = CreateRectRgn( pRect->left, pRect->top,
+ pRect->right, pRect->bottom );
+ }
+ else
+ {
+ sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
+ hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
+ if ( mpClipRgnData != mpStdClipRgnData )
+ delete [] (BYTE*)mpClipRgnData;
+ }
+
+ DBG_ASSERT( hRegion, "SalObject::EndSetClipRegion() - Can't create ClipRegion" );
+ SetWindowRgn( mhWnd, hRegion, TRUE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
+{
+ sal_uLong nStyle = 0;
+ sal_Bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
+ if ( bVisible )
+ {
+ ShowWindow( mhWnd, SW_HIDE );
+ nStyle |= SWP_SHOWWINDOW;
+ }
+ SetWindowPos( mhWnd, 0,
+ (int)nX, (int)nY, (int)nWidth, (int)nHeight,
+ SWP_NOZORDER | SWP_NOACTIVATE | nStyle );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::Show( sal_Bool bVisible )
+{
+ if ( bVisible )
+ ShowWindow( mhWnd, SW_SHOWNORMAL );
+ else
+ ShowWindow( mhWnd, SW_HIDE );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::Enable( sal_Bool bEnable )
+{
+ EnableWindow( mhWnd, bEnable );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::GrabFocus()
+{
+ if ( mhLastFocusWnd &&
+ IsWindow( mhLastFocusWnd ) &&
+ ImplIsSysWindowOrChild( mhWndChild, mhLastFocusWnd ) )
+ ::SetFocus( mhLastFocusWnd );
+ else
+ ::SetFocus( mhWndChild );
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetBackground()
+{
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::SetBackground( SalColor )
+{
+}
+
+// -----------------------------------------------------------------------
+
+const SystemEnvData* WinSalObject::GetSystemData() const
+{
+ return &maSysData;
+}
+
+// -----------------------------------------------------------------------
+
+void WinSalObject::InterceptChildWindowKeyDown( sal_Bool bIntercept )
+{
+ mbInterceptChildWindowKeyDown = bIntercept;
+}
+