diff options
Diffstat (limited to 'vcl/win')
120 files changed, 25638 insertions, 0 deletions
diff --git a/vcl/win/inc/salbmp.h b/vcl/win/inc/salbmp.h new file mode 100644 index 000000000000..0c8129bbbb99 --- /dev/null +++ b/vcl/win/inc/salbmp.h @@ -0,0 +1,91 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salbmp.h,v $ + * $Revision: 1.6 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALBMP_H +#define _SV_SALBMP_H + +#include <wincomp.hxx> +#include <tools/gen.hxx> +#include <vcl/sv.h> +#include <vcl/salbmp.hxx> + +// -------------- +// - SalBitmap - +// -------------- + +struct BitmapBuffer; +class BitmapColor; +class BitmapPalette; +class SalGraphics; + +class WinSalBitmap : public SalBitmap +{ +private: + + Size maSize; + HGLOBAL mhDIB; + HBITMAP mhDDB; + USHORT mnBitCount; + +public: + + HGLOBAL ImplGethDIB() const { return mhDIB; } + HBITMAP ImplGethDDB() const { return mhDDB; } + + static HGLOBAL ImplCreateDIB( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal ); + static HANDLE ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB ); + static USHORT ImplGetDIBColorCount( HGLOBAL hDIB ); + static void ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf, + const Size& rSizePixel, bool bRLE4 ); + +public: + + WinSalBitmap(); + virtual ~WinSalBitmap(); + +public: + + bool Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle ); + virtual bool Create( const Size& rSize, USHORT nBitCount, const BitmapPalette& rPal ); + virtual bool Create( const SalBitmap& rSalBmpImpl ); + virtual bool Create( const SalBitmap& rSalBmpImpl, SalGraphics* pGraphics ); + virtual bool Create( const SalBitmap& rSalBmpImpl, USHORT nNewBitCount ); + + virtual void Destroy(); + + virtual Size GetSize() const { return maSize; } + virtual USHORT GetBitCount() const { return mnBitCount; } + + virtual BitmapBuffer* AcquireBuffer( bool bReadOnly ); + virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ); + virtual bool GetSystemData( BitmapSystemData& rData ); +}; + +#endif // _SV_SALBMP_HXX diff --git a/vcl/win/inc/saldata.hxx b/vcl/win/inc/saldata.hxx new file mode 100644 index 000000000000..d743a7b7dae1 --- /dev/null +++ b/vcl/win/inc/saldata.hxx @@ -0,0 +1,375 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: saldata.hxx,v $ + * $Revision: 1.30 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALDATA_HXX +#define _SV_SALDATA_HXX + +#include <vcl/sv.h> +#include <vcl/svdata.hxx> +#include <vcl/salwtype.hxx> +#include <wincomp.hxx> + +#include <set> // for hMenu validation +#include <map> + +class AutoTimer; +class WinSalInstance; +class WinSalObject; +class WinSalFrame; +class WinSalVirtualDevice; +class WinSalPrinter; +class Font; +struct HDCCache; +struct TempFontItem; + +// -------------------- +// - Standard-Defines - +// -------------------- + +#define MAX_STOCKPEN 4 +#define MAX_STOCKBRUSH 4 +#define SAL_CLIPRECT_COUNT 16 + +// -------------------- +// - Icon cache - +// -------------------- + +struct SalIcon +{ + int nId; + HICON hIcon; + HICON hSmallIcon; + SalIcon *pNext; +}; + +// ----------- +// - SalData - +// ----------- + +class SalData +{ +public: + SalData(); + ~SalData(); + + // native widget framework + void initNWF(); + void deInitNWF(); + + // fill maVKMap; + void initKeyCodeMap(); + + // checks if the menuhandle was created by VCL + BOOL IsKnownMenuHandle( HMENU hMenu ); + +public: + HINSTANCE mhInst; // default instance handle + HINSTANCE mhPrevInst; // previous instance handle + int mnCmdShow; // default frame show style + HPALETTE mhDitherPal; // dither palette + HGLOBAL mhDitherDIB; // dither memory handle + BYTE* mpDitherDIB; // dither memory + BYTE* mpDitherDIBData; // beginning of DIB data + long* mpDitherDiff; // Dither mapping table + BYTE* mpDitherLow; // Dither mapping table + BYTE* mpDitherHigh; // Dither mapping table + ULONG mnTimerMS; // Current Time (in MS) of the Timer + ULONG mnTimerOrgMS; // Current Original Time (in MS) + DWORD mnNextTimerTime; + DWORD mnLastEventTime; + UINT mnTimerId; // windows timer id + BOOL mbInTimerProc; // timer event is currently being dispatched + HHOOK mhSalObjMsgHook; // hook to get interesting msg for SalObject + HWND mhWantLeaveMsg; // window handle, that want a MOUSELEAVE message + AutoTimer* mpMouseLeaveTimer; // Timer for MouseLeave Test + WinSalInstance* mpFirstInstance; // pointer of first instance + WinSalFrame* mpFirstFrame; // pointer of first frame + WinSalObject* mpFirstObject; // pointer of first object window + WinSalVirtualDevice* mpFirstVD; // first VirDev + WinSalPrinter* mpFirstPrinter; // first printing printer + HDCCache* mpHDCCache; // Cache for three DC's + HBITMAP mh50Bmp; // 50% Bitmap + HBRUSH mh50Brush; // 50% Brush + COLORREF maStockPenColorAry[MAX_STOCKPEN]; + COLORREF maStockBrushColorAry[MAX_STOCKBRUSH]; + HPEN mhStockPenAry[MAX_STOCKPEN]; + HBRUSH mhStockBrushAry[MAX_STOCKBRUSH]; + USHORT mnStockPenCount; // count of static pens + USHORT mnStockBrushCount; // count of static brushes + WPARAM mnSalObjWantKeyEvt; // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll + BYTE mnCacheDCInUse; // count of CacheDC in use + BOOL mbObjClassInit; // is SALOBJECTCLASS initialised + BOOL mbInPalChange; // is in WM_QUERYNEWPALETTE + DWORD mnAppThreadId; // Id from Applikation-Thread + WIN_BOOL mbScrSvrEnabled; // ScreenSaver enabled + int mnSageStatus; // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden) + SysAgt_Enable_PROC mpSageEnableProc; // funktion to deactivate the system agent + SalIcon* mpFirstIcon; // icon cache, points to first icon, NULL if none + TempFontItem* mpTempFontItem; + BOOL mbThemeChanged; // true if visual theme was changed: throw away theme handles + + // for GdiPlus GdiplusStartup/GdiplusShutdown + ULONG_PTR gdiplusToken; + + std::set< HMENU > mhMenuSet; // keeps track of menu handles created by VCL, used by IsKnownMenuHandle() + std::map< UINT,USHORT > maVKMap; // map some dynamic VK_* entries +}; + +inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = (void*)pData; } +inline SalData* GetSalData() { return (SalData*)ImplGetSVData()->mpSalData; } +inline SalData* GetAppSalData() { return (SalData*)ImplGetAppSVData()->mpSalData; } + +// -------------- +// - SalShlData - +// -------------- + +struct SalShlData +{ + HINSTANCE mhInst; // Instance of SAL-DLL + UINT mnWheelScrollLines; // WheelScrollLines + UINT mnWheelScrollChars; // WheelScrollChars + UINT mnWheelMsgId; // Wheel-Message-Id fuer W95 + WORD mnVersion; // System-Version (311 == 3.11) + WIN_BOOL mbWNT; // kein W16/W95/W98 sondern ein NT + WIN_BOOL mbW40; // Is System-Version >= 4.0 + WIN_BOOL mbWXP; // Windows XP + WIN_BOOL mbWPrinter; // true: use unicode printer functions + // false: use anis compat printer functions + OSVERSIONINFO maVersionInfo; +}; + +extern SalShlData aSalShlData; + +// ------------ +// - GDICache - +// ------------ + +#define CACHESIZE_HDC 3 +#define CACHED_HDC_1 0 +#define CACHED_HDC_2 1 +#define CACHED_HDC_DRAW 2 +#define CACHED_HDC_DEFEXT 64 + +struct HDCCache +{ + HDC mhDC; + HPALETTE mhDefPal; + HBITMAP mhDefBmp; + HBITMAP mhSelBmp; + HBITMAP mhActBmp; +}; + +void ImplClearHDCCache( SalData* pData ); +HDC ImplGetCachedDC( ULONG nID, HBITMAP hBmp = 0 ); +void ImplReleaseCachedDC( ULONG nID ); + +bool ImplAddTempFont( SalData&, const String& rFontFileURL ); +void ImplReleaseTempFonts( SalData& ); + +// -------------------------------------------- +// - SALSHL.CXX - for accessing DLL resources - +// -------------------------------------------- + +HCURSOR ImplLoadSalCursor( int nId ); +HBITMAP ImplLoadSalBitmap( int nId ); +BOOL ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon ); + +// SALGDI.CXX +void ImplInitSalGDI(); +void ImplFreeSalGDI(); + +// -------------- +// - Prototypes - +// -------------- + +// \\WIN\SOURCE\APP\SALINST.CXX +void ImplSalYieldMutexAcquireWithWait(); +BOOL ImplSalYieldMutexTryToAcquire(); +void ImplSalYieldMutexAcquire(); +void ImplSalYieldMutexRelease(); +ULONG ImplSalReleaseYieldMutex(); +void ImplSalAcquireYieldMutex( ULONG nCount ); + +// \\WIN\SOURCE\WINDOW\SALFRAME.CXX +LRESULT CALLBACK SalFrameWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); +LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); +// \SV\WIN\SOURCE\APP\SALTIMER.CXX +#define SALTIMERPROC_RECURSIVE 0xffffffff +void CALLBACK SalTimerProc( HWND hWnd, UINT nMsg, UINT_PTR nId, DWORD nTime ); + +// \WIN\SOURCE\WINDOW\SALFRAME.CXX +void SalTestMouseLeave(); +BOOL ImplWriteLastError( DWORD lastError, const char *szApiCall ); + +// \WIN\SOURCE\WINDOW\SALFRAME.CXX +long ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); +long ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam ); +BOOL ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult ); + +// \WIN\SOURCE\WINDOW\SALOBJ.CXX +WinSalObject* ImplFindSalObject( HWND hWndChild ); +BOOL ImplSalPreDispatchMsg( MSG* pMsg ); +void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT nDispatchResult ); + +// \WIN\SOURCE\GDI\SALGDI3.CXX +void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont ); +void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont ); +bool ImplIsFontAvailable( HDC hDC, const UniString& rName ); + +// \WIN\SOURCE\APP\SALDATA.CXX +rtl_TextEncoding ImplSalGetSystemEncoding(); +ByteString ImplSalGetWinAnsiString( const UniString& rStr, BOOL bFileName = FALSE ); +UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN ); +int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); + +// ----------- +// - Defines - +// ----------- + +#define SAL_FRAME_WNDEXTRA sizeof( DWORD ) +#define SAL_FRAME_THIS 0 +#define SAL_FRAME_CLASSNAMEA "SALFRAME" +#define SAL_FRAME_CLASSNAMEW L"SALFRAME" +#define SAL_SUBFRAME_CLASSNAMEA "SALSUBFRAME" +#define SAL_SUBFRAME_CLASSNAMEW L"SALSUBFRAME" +#define SAL_TMPSUBFRAME_CLASSNAMEW L"SALTMPSUBFRAME" +#define SAL_OBJECT_WNDEXTRA sizeof( DWORD ) +#define SAL_OBJECT_THIS 0 +#define SAL_OBJECT_CLASSNAMEA "SALOBJECT" +#define SAL_OBJECT_CLASSNAMEW L"SALOBJECT" +#define SAL_OBJECT_CHILDCLASSNAMEA "SALOBJECTCHILD" +#define SAL_OBJECT_CHILDCLASSNAMEW L"SALOBJECTCHILD" +#define SAL_COM_CLASSNAMEA "SALCOMWND" +#define SAL_COM_CLASSNAMEW L"SALCOMWND" + +#define SAL_MOUSELEAVE_TIMEOUT 300 + +// wParam == hDC; lParam == 0 +#define SAL_MSG_PRINTABORTJOB (WM_USER+110) +// wParam == bWait; lParam == 0 +#define SAL_MSG_THREADYIELD (WM_USER+111) +// wParam == 0; lParam == 0 +#define SAL_MSG_RELEASEWAITYIELD (WM_USER+112) +// wParam == 0; lParam == nMS +#define SAL_MSG_STARTTIMER (WM_USER+113) +// wParam == nFrameStyle; lParam == pParent; lResult == pFrame +#define SAL_MSG_CREATEFRAME (WM_USER+114) +// wParam == 0; lParam == 0 +#define SAL_MSG_DESTROYFRAME (WM_USER+115) +// wParam == 0; lParam == pParent; lResult == pObject +#define SAL_MSG_CREATEOBJECT (WM_USER+116) +// wParam == 0; lParam == pObject; +#define SAL_MSG_DESTROYOBJECT (WM_USER+117) +// wParam == hWnd; lParam == 0; lResult == hDC +#define SAL_MSG_GETDC (WM_USER+120) +// wParam == hWnd; lParam == 0 +#define SAL_MSG_RELEASEDC (WM_USER+121) +// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd +#define SAL_MSG_RECREATEHWND (WM_USER+122) +// wParam == newParentHwnd; lParam == oldHwnd; lResult == newhWnd +#define SAL_MSG_RECREATECHILDHWND (WM_USER+123) +// wParam == 0; lParam == HWND; +#define SAL_MSG_DESTROYHWND (WM_USER+124) + +// wParam == 0; lParam == pData +#define SAL_MSG_USEREVENT (WM_USER+130) +// wParam == 0; lParam == MousePosition relativ to upper left of screen +#define SAL_MSG_MOUSELEAVE (WM_USER+131) +// NULL-Message, soll nicht verarbeitet werden +#define SAL_MSG_DUMMY (WM_USER+132) +// wParam == 0; lParam == 0 +#define SAL_MSG_POSTFOCUS (WM_USER+133) +// wParam == wParam; lParam == lParam +#define SAL_MSG_POSTQUERYNEWPAL (WM_USER+134) +// wParam == wParam; lParam == lParam +#define SAL_MSG_POSTPALCHANGED (WM_USER+135) +// wParam == wParam; lParam == lParam +#define SAL_MSG_POSTMOVE (WM_USER+136) +// wParam == wParam; lParam == lParam +#define SAL_MSG_POSTCALLSIZE (WM_USER+137) +// wParam == pRECT; lParam == 0 +#define SAL_MSG_POSTPAINT (WM_USER+138) +// wParam == 0; lParam == pFrame; lResult 0 +#define SAL_MSG_FORCEPALETTE (WM_USER+139) +// wParam == 0; lParam == 0 +#define SAL_MSG_CAPTUREMOUSE (WM_USER+140) +// wParam == 0; lParam == 0 +#define SAL_MSG_RELEASEMOUSE (WM_USER+141) +// wParam == nFlags; lParam == 0 +#define SAL_MSG_TOTOP (WM_USER+142) +// wParam == bVisible; lParam == 0 +#define SAL_MSG_SHOW (WM_USER+143) +// wParam == 0; lParam == SalInputContext +#define SAL_MSG_SETINPUTCONTEXT (WM_USER+144) +// wParam == nFlags; lParam == 0 +#define SAL_MSG_ENDEXTTEXTINPUT (WM_USER+145) +// POSTTIMER-Message; wparam = 0, lParam == time +#define SAL_MSG_POSTTIMER (WM_USER+161) + +// SysChild-ToTop; wParam = 0; lParam = 0 +#define SALOBJ_MSG_TOTOP (WM_USER+160) +// POSTFOCUS-Message; wParam == bFocus; lParam == 0 +#define SALOBJ_MSG_POSTFOCUS (WM_USER+161) + + +// ----------------- +// - Helpfunctions - +// ----------------- + +// A/W-Wrapper +LONG ImplSetWindowLong( HWND hWnd, int nIndex, DWORD dwNewLong ); +LONG ImplGetWindowLong( HWND hWnd, int nIndex ); +WIN_BOOL ImplPostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); +WIN_BOOL ImplSendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ); +WIN_BOOL ImplGetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ); +WIN_BOOL ImplPeekMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ); +LONG ImplDispatchMessage( CONST MSG *lpMsg ); + +inline void SetWindowPtr( HWND hWnd, WinSalFrame* pThis ) +{ + ImplSetWindowLong( hWnd, SAL_FRAME_THIS, (LONG)pThis ); +} + +inline WinSalFrame* GetWindowPtr( HWND hWnd ) +{ + return (WinSalFrame*)ImplGetWindowLong( hWnd, SAL_FRAME_THIS ); +} + +inline void SetSalObjWindowPtr( HWND hWnd, WinSalObject* pThis ) +{ + ImplSetWindowLong( hWnd, SAL_OBJECT_THIS, (LONG)pThis ); +} + +inline WinSalObject* GetSalObjWindowPtr( HWND hWnd ) +{ + return (WinSalObject*)ImplGetWindowLong( hWnd, SAL_OBJECT_THIS ); +} + +#endif // _SV_SALDATA_HXX diff --git a/vcl/win/inc/salframe.h b/vcl/win/inc/salframe.h new file mode 100644 index 000000000000..b29ce49e0d74 --- /dev/null +++ b/vcl/win/inc/salframe.h @@ -0,0 +1,153 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salframe.h,v $ + * $Revision: 1.22 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALFRAME_H +#define _SV_SALFRAME_H + +#include <vcl/sv.h> +#include <vcl/sysdata.hxx> +#include <vcl/salframe.hxx> + +class WinSalGraphics; + +// ---------------- +// - WinSalFrame - +// ---------------- + +class WinSalFrame : public SalFrame +{ +public: + HWND mhWnd; // Window handle + HCURSOR mhCursor; // cursor handle + HIMC mhDefIMEContext; // default IME-Context + WinSalGraphics* mpGraphics; // current frame graphics + WinSalGraphics* mpGraphics2; // current frame graphics for other threads + WinSalFrame* mpNextFrame; // pointer to next frame + HMENU mSelectedhMenu; // the menu where highlighting is currently going on + HMENU mLastActivatedhMenu; // the menu that was most recently opened + SystemEnvData maSysData; // system data + SalFrameState maState; // frame state + int mnShowState; // show state + long mnWidth; // client width in pixeln + long mnHeight; // client height in pixeln + int mnMinWidth; // min. client width in pixeln + int mnMinHeight; // min. client height in pixeln + int mnMaxWidth; // max. client width in pixeln + int mnMaxHeight; // max. client height in pixeln + RECT maFullScreenRect; // fullscreen rect + int mnFullScreenShowState; // fullscreen restore show state + UINT mnInputLang; // current Input Language + UINT mnInputCodePage; // current Input CodePage + ULONG mnStyle; // style + BOOL mbGraphics; // is Graphics used + BOOL mbCaption; // has window a caption + BOOL mbBorder; // has window a border + BOOL mbFixBorder; // has window a fixed border + BOOL mbSizeBorder; // has window a sizeable border + BOOL mbNoIcon; // is an window without an icon + BOOL mbFloatWin; // is a FloatingWindow + BOOL mbFullScreen; // TRUE: in full screen mode + BOOL mbPresentation; // TRUE: Presentation Mode running + BOOL mbInShow; // innerhalb eines Show-Aufrufs + BOOL mbRestoreMaximize; // Restore-Maximize + BOOL mbInMoveMsg; // Move-Message wird verarbeitet + BOOL mbInSizeMsg; // Size-Message wird verarbeitet + BOOL mbFullScreenToolWin; // WS_EX_TOOLWINDOW reset in FullScreenMode + BOOL mbDefPos; // default-position + BOOL mbOverwriteState; // TRUE: WindowState darf umgesetzt werden + BOOL mbIME; // TRUE: We are in IME Mode + BOOL mbHandleIME; // TRUE: Wir handeln die IME-Messages + BOOL mbSpezIME; // TRUE: Spez IME + BOOL mbAtCursorIME; // TRUE: Wir behandeln nur einige IME-Messages + BOOL mbCandidateMode; // TRUE: Wir befinden uns im Candidate-Modus + static BOOL mbInReparent; // TRUE: ignore focus lost and gain due to reparenting + + RGNDATA* mpClipRgnData; + RECT* mpNextClipRect; + BOOL mbFirstClipRect; + sal_Int32 mnDisplay; // Display used for Fullscreen, 0 is primary monitor + + void updateScreenNumber(); +public: + WinSalFrame(); + virtual ~WinSalFrame(); + + virtual SalGraphics* GetGraphics(); + virtual void ReleaseGraphics( SalGraphics* pGraphics ); + virtual BOOL PostEvent( void* pData ); + virtual void SetTitle( const XubString& rTitle ); + virtual void SetIcon( USHORT nIcon ); + virtual void SetMenu( SalMenu* pSalMenu ); + virtual void DrawMenuBar(); + virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ); + virtual void Show( BOOL bVisible, BOOL bNoActivate = FALSE ); + virtual void Enable( BOOL bEnable ); + virtual void SetMinClientSize( long nWidth, long nHeight ); + virtual void SetMaxClientSize( long nWidth, long nHeight ); + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, USHORT nFlags ); + virtual void GetClientSize( long& rWidth, long& rHeight ); + virtual void GetWorkArea( Rectangle& rRect ); + virtual SalFrame* GetParent() const; + virtual void SetWindowState( const SalFrameState* pState ); + virtual BOOL GetWindowState( SalFrameState* pState ); + virtual void ShowFullScreen( BOOL bFullScreen, sal_Int32 nDisplay ); + virtual void StartPresentation( BOOL bStart ); + virtual void SetAlwaysOnTop( BOOL bOnTop ); + virtual void ToTop( USHORT nFlags ); + virtual void SetPointer( PointerStyle ePointerStyle ); + virtual void CaptureMouse( BOOL bMouse ); + virtual void SetPointerPos( long nX, long nY ); + using SalFrame::Flush; + virtual void Flush(); + virtual void Sync(); + virtual void SetInputContext( SalInputContext* pContext ); + virtual void EndExtTextInput( USHORT nFlags ); + virtual String GetKeyName( USHORT nKeyCode ); + virtual String GetSymbolKeyName( const XubString& rFontName, USHORT nKeyCode ); + virtual BOOL MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode ); + virtual LanguageType GetInputLanguage(); + virtual SalBitmap* SnapShot(); + virtual void UpdateSettings( AllSettings& rSettings ); + virtual void Beep( SoundType eSoundType ); + virtual const SystemEnvData* GetSystemData() const; + virtual SalPointerState GetPointerState(); + virtual void SetParent( SalFrame* pNewParent ); + virtual bool SetPluginParent( SystemParentData* pNewParent ); + virtual void SetBackgroundBitmap( SalBitmap* ); + virtual void SetScreenNumber( unsigned int ); + virtual void ResetClipRegion(); + virtual void BeginSetClipRegion( ULONG nRects ); + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ); + virtual void EndSetClipRegion(); +}; + +void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect ); + +#endif // _SV_SALFRAME_H diff --git a/vcl/win/inc/salgdi.h b/vcl/win/inc/salgdi.h new file mode 100644 index 000000000000..c7ceb68199b9 --- /dev/null +++ b/vcl/win/inc/salgdi.h @@ -0,0 +1,406 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salgdi.h,v $ + * $Revision: 1.30.20.5 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALGDI_H +#define _SV_SALGDI_H + +#include <vcl/sv.h> +#include <vcl/sallayout.hxx> +#include <vcl/salgdi.hxx> +#include <vcl/outfont.hxx> +#include <vcl/impfont.hxx> + +#include "boost/scoped_ptr.hpp" +#include <hash_set> + +class ImplFontSelectData; +class ImplWinFontEntry; +class ImplFontAttrCache; + +// ----------- +// - Defines - +// ----------- + +#define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000) +#define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff) + +// win32 platform specific options. Move them to the PMK file? + +#define GCP_KERN_HACK +#define GNG_VERT_HACK + +// win32 specific physically available font face +class ImplWinFontData : public ImplFontData +{ +public: + ImplWinFontData( const ImplDevFontAttributes&, + int nFontHeight, WIN_BYTE eWinCharSet, + WIN_BYTE nPitchAndFamily ); + ~ImplWinFontData(); + + virtual ImplFontData* Clone() const; + virtual ImplFontEntry* CreateFontInstance( ImplFontSelectData& ) const; + virtual sal_IntPtr GetFontId() const; + void SetFontId( sal_IntPtr nId ) { mnId = nId; } + void UpdateFromHDC( HDC ) const; + + bool HasChar( sal_uInt32 cChar ) const; + + WIN_BYTE GetCharSet() const { return meWinCharSet; } + WIN_BYTE GetPitchAndFamily() const { return mnPitchAndFamily; } + bool IsGlyphApiDisabled() const { return mbDisableGlyphApi; } + bool SupportsKorean() const { return mbHasKoreanRange; } + bool SupportsCJK() const { return mbHasCJKSupport; } + bool SupportsArabic() const { return mbHasArabicSupport; } + bool AliasSymbolsHigh() const { return mbAliasSymbolsHigh; } + bool AliasSymbolsLow() const { return mbAliasSymbolsLow; } +#ifdef ENABLE_GRAPHITE + bool SupportsGraphite() const { return mbHasGraphiteSupport; } +#endif + + ImplFontCharMap* GetImplFontCharMap() const; + const Ucs2SIntMap* GetEncodingVector() const { return mpEncodingVector; } + void SetEncodingVector( const Ucs2SIntMap* pNewVec ) const + { + if( mpEncodingVector ) + delete mpEncodingVector; + mpEncodingVector = pNewVec; + } +private: + sal_IntPtr mnId; + + // some members that are initalized lazily when the font gets selected into a HDC + mutable bool mbDisableGlyphApi; + mutable bool mbHasKoreanRange; + mutable bool mbHasCJKSupport; +#ifdef ENABLE_GRAPHITE + mutable bool mbHasGraphiteSupport; +#endif + mutable bool mbHasArabicSupport; + mutable ImplFontCharMap* mpUnicodeMap; + mutable const Ucs2SIntMap* mpEncodingVector; + + // TODO: get rid of the members below needed to work with the Win9x non-unicode API + BYTE* mpFontCharSets; // all Charsets for the current font (used on W98 for kerning) + BYTE mnFontCharSetCount; // Number of Charsets of the current font; 0 - if not queried + WIN_BYTE meWinCharSet; + WIN_BYTE mnPitchAndFamily; + bool mbAliasSymbolsHigh; + bool mbAliasSymbolsLow; +private: + void ReadCmapTable( HDC ) const; + void ReadOs2Table( HDC ) const; + +#ifdef GNG_VERT_HACK + void ReadGsubTable( HDC ) const; + + typedef std::hash_set<sal_UCS4> UcsHashSet; + mutable UcsHashSet maGsubTable; + mutable bool mbGsubRead; +public: + bool HasGSUBstitutions( HDC ) const; + bool IsGSUBstituted( sal_UCS4 ) const; +#endif // GNG_VERT_HACK +}; + +// ------------------- +// - SalGraphicsData - +// ------------------- + +class WinSalGraphics : public SalGraphics +{ +public: + HDC mhDC; // HDC + HWND mhWnd; // Window-Handle, when Window-Graphics + HFONT mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks + const ImplWinFontData* mpWinFontData[ MAX_FALLBACK ]; // pointer to the most recent font face + ImplWinFontEntry* mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance + float mfFontScale; // allows metrics emulation of huge font sizes + HPEN mhPen; // Pen + HBRUSH mhBrush; // Brush + HRGN mhRegion; // Region Handle + HPEN mhDefPen; // DefaultPen + HBRUSH mhDefBrush; // DefaultBrush + HFONT mhDefFont; // DefaultFont + HPALETTE mhDefPal; // DefaultPalette + COLORREF mnPenColor; // PenColor + COLORREF mnBrushColor; // BrushColor + COLORREF mnTextColor; // TextColor + RGNDATA* mpClipRgnData; // ClipRegion-Data + RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data + RECT* mpNextClipRect; // Naechstes ClipRegion-Rect + BOOL mbFirstClipRect; // Flag for first cliprect to insert + LOGFONTA* mpLogFont; // LOG-Font which is currently selected (only W9x) + ImplFontAttrCache* mpFontAttrCache; // Cache font attributes from files in so/share/fonts + BYTE* mpFontCharSets; // All Charsets for the current font + BYTE mnFontCharSetCount; // Number of Charsets of the current font; 0 - if not queried + BOOL mbFontKernInit; // FALSE: FontKerns must be queried + KERNINGPAIR* mpFontKernPairs; // Kerning Pairs of the current Font + ULONG mnFontKernPairCount;// Number of Kerning Pairs of the current Font + int mnPenWidth; // Linienbreite + BOOL mbStockPen; // is Pen a stockpen + BOOL mbStockBrush; // is Brush a stcokbrush + BOOL mbPen; // is Pen (FALSE == NULL_PEN) + BOOL mbBrush; // is Brush (FALSE == NULL_BRUSH) + BOOL mbPrinter; // is Printer + BOOL mbVirDev; // is VirDev + BOOL mbWindow; // is Window + BOOL mbScreen; // is Screen compatible + bool mbXORMode; // _every_ output with RasterOp XOR + + // remember RGB values for SetLineColor/SetFillColor + SalColor maLineColor; + SalColor maFillColor; + + HFONT ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont ); + +public: + WinSalGraphics(); + virtual ~WinSalGraphics(); + +protected: + virtual BOOL unionClipRegion( long nX, long nY, long nWidth, long nHeight ); + virtual bool unionClipRegion( const ::basegfx::B2DPolyPolygon& ); + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ); + virtual void drawPixel( long nX, long nY, SalColor nSalColor ); + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ); + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ); + virtual void drawPolyLine( ULONG nPoints, const SalPoint* pPtAry ); + virtual void drawPolygon( ULONG nPoints, const SalPoint* pPtAry ); + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ); + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ); + virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin); + virtual sal_Bool drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ); + virtual sal_Bool drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ); + virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ); + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, USHORT nFlags ); + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics ); + virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ); + virtual void drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ); + virtual void drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ); + virtual void drawMask( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ); + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ); + virtual SalColor getPixel( long nX, long nY ); + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags); + virtual void invert( ULONG nPoints, const SalPoint* pPtAry, SalInvert nFlags ); + + virtual BOOL drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize ); + + // native widget rendering methods that require mirroring + virtual BOOL hitTestNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion, + const Point& aPos, SalControlHandle& rControlHandle, BOOL& rIsInside ); + virtual BOOL drawNativeControl( ControlType nType, ControlPart nPart, const Region& rControlRegion, + ControlState nState, const ImplControlValue& aValue, SalControlHandle& rControlHandle, + const rtl::OUString& aCaption ); + virtual BOOL drawNativeControlText( ControlType nType, ControlPart nPart, const Region& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + SalControlHandle& rControlHandle, const rtl::OUString& aCaption ); + virtual BOOL getNativeControlRegion( ControlType nType, ControlPart nPart, const Region& rControlRegion, ControlState nState, + const ImplControlValue& aValue, SalControlHandle& rControlHandle, const rtl::OUString& aCaption, + Region &rNativeBoundingRegion, Region &rNativeContentRegion ); + + virtual bool drawAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ); + virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ); + +public: + // public SalGraphics methods, the interface to teh independent vcl part + + // get device resolution + virtual void GetResolution( long& rDPIX, long& rDPIY ); + // get the depth of the device + virtual USHORT GetBitCount(); + // get the width of the device + virtual long GetGraphicsWidth() const; + + // set the clip region to empty + virtual void ResetClipRegion(); + // begin setting the clip region, add rectangles to the + // region with the UnionClipRegion call + virtual void BeginSetClipRegion( ULONG nCount ); + // all rectangles were added and the clip region should be set now + virtual void EndSetClipRegion(); + + // set the line color to transparent (= don't draw lines) + virtual void SetLineColor(); + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ); + // set the fill color to transparent (= don't fill) + virtual void SetFillColor(); + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ); + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool ); + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ); + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ); + // set the text color to a specific color + virtual void SetTextColor( SalColor nSalColor ); + // set the font + virtual USHORT SetFont( ImplFontSelectData*, int nFallbackLevel ); + // get the current font's etrics + virtual void GetFontMetric( ImplFontMetricData* ); + // get kernign pairs of the current font + // return only PairCount if (pKernPairs == NULL) + virtual ULONG GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs ); + // get the repertoire of the current font + virtual ImplFontCharMap* GetImplFontCharMap() const; + // graphics must fill supplied font list + virtual void GetDevFontList( ImplDevFontList* ); + // graphics should call ImplAddDevFontSubstitute on supplied + // OutputDevice for all its device specific preferred font substitutions + virtual void GetDevFontSubstList( OutputDevice* ); + virtual bool AddTempDevFont( ImplDevFontList*, const String& rFileURL, const String& rFontName ); + // CreateFontSubset: a method to get a subset of glyhps of a font + // inside a new valid font file + // returns TRUE if creation of subset was successfull + // parameters: rToFile: contains a osl file URL to write the subset to + // pFont: describes from which font to create a subset + // pGlyphIDs: the glyph ids to be extracted + // pEncoding: the character code corresponding to each glyph + // pWidths: the advance widths of the correspoding glyphs (in PS font units) + // nGlyphs: the number of glyphs + // rInfo: additional outgoing information + // implementation note: encoding 0 with glyph id 0 should be added implicitly + // as "undefined character" + virtual BOOL CreateFontSubset( const rtl::OUString& rToFile, + const ImplFontData*, + long* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo // out parameter + ); + + // GetFontEncodingVector: a method to get the encoding map Unicode + // to font encoded character; this is only used for type1 fonts and + // may return NULL in case of unknown encoding vector + // if ppNonEncoded is set and non encoded characters (that is type1 + // glyphs with only a name) exist it is set to the corresponding + // map for non encoded glyphs; the encoding vector contains -1 + // as encoding for these cases + virtual const Ucs2SIntMap* GetFontEncodingVector( const ImplFontData*, const Ucs2OStrMap** ppNonEncoded ); + + // GetEmbedFontData: gets the font data for a font marked + // embeddable by GetDevFontList or NULL in case of error + // parameters: pFont: describes the font in question + // pWidths: the widths of all glyphs from char code 0 to 255 + // pWidths MUST support at least 256 members; + // rInfo: additional outgoing information + // pDataLen: out parameter, contains the byte length of the returned buffer + virtual const void* GetEmbedFontData( const ImplFontData*, + const sal_Ucs* pUnicodes, + sal_Int32* pWidths, + FontSubsetInfo& rInfo, + long* pDataLen ); + // frees the font data again + virtual void FreeEmbedFontData( const void* pData, long nDataLen ); + virtual void GetGlyphWidths( const ImplFontData*, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ); + virtual int GetMinKashidaWidth(); + + virtual BOOL GetGlyphBoundRect( long nIndex, Rectangle& ); + virtual BOOL GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& ); + + virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ); + virtual void DrawServerFontLayout( const ServerFontLayout& ); + + virtual bool supportsOperation( OutDevSupportType ) const; + // Query the platform layer for control support + virtual BOOL IsNativeControlSupported( ControlType nType, ControlPart nPart ); + + virtual SystemGraphicsData GetGraphicsData() const; + virtual SystemFontData GetSysFontData( int nFallbacklevel ) const; +}; + +// Init/Deinit Graphics +void ImplSalInitGraphics( WinSalGraphics* mpData ); +void ImplSalDeInitGraphics( WinSalGraphics* mpData ); +void ImplUpdateSysColorEntries(); +int ImplIsSysColorEntry( SalColor nSalColor ); +void ImplGetLogFontFromFontSelect( HDC hDC, const ImplFontSelectData*, + LOGFONTW&, bool bTestVerticalAvail ); + +// ----------- +// - Defines - +// ----------- + +#define MAX_64KSALPOINTS ((((USHORT)0xFFFF)-8)/sizeof(POINTS)) + +// ----------- +// - Inlines - +// ----------- + +// #102411# Win's GCP mishandles kerning => we need to do it ourselves +// SalGraphicsData::mpFontKernPairs is sorted by +inline bool ImplCmpKernData( const KERNINGPAIR& a, const KERNINGPAIR& b ) +{ + if( a.wFirst < b.wFirst ) + return true; + if( a.wFirst > b.wFirst ) + return false; + return (a.wSecond < b.wSecond); +} + +// called extremely often from just one spot => inline +inline bool ImplWinFontData::HasChar( sal_uInt32 cChar ) const +{ + if( mpUnicodeMap->HasChar( cChar ) ) + return true; + // second chance to allow symbol aliasing + if( mbAliasSymbolsLow && ((cChar-0xF000) <= 0xFF) ) + cChar -= 0xF000; + else if( mbAliasSymbolsHigh && (cChar <= 0xFF) ) + cChar += 0xF000; + return mpUnicodeMap->HasChar( cChar ); +} + +#endif // _SV_SALGDI_H diff --git a/vcl/win/inc/salids.hrc b/vcl/win/inc/salids.hrc new file mode 100644 index 000000000000..712c5a58d0bd --- /dev/null +++ b/vcl/win/inc/salids.hrc @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salids.hrc,v $ + * $Revision: 1.6 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALIDS_HRC +#define _SV_SALIDS_HRC + +// Cursor +#define SAL_RESID_POINTER_NULL 10000 +#ifndef W40ONLY +#define SAL_RESID_POINTER_HELP 10001 +#endif +#ifndef WNT +#define SAL_RESID_POINTER_HSIZE 10002 +#define SAL_RESID_POINTER_VSIZE 10003 +#define SAL_RESID_POINTER_NESWSIZE 10004 +#define SAL_RESID_POINTER_NWSESIZE 10005 +#endif +#define SAL_RESID_POINTER_CROSS 10006 +#define SAL_RESID_POINTER_MOVE 10007 +#define SAL_RESID_POINTER_HSPLIT 10008 +#define SAL_RESID_POINTER_VSPLIT 10009 +#define SAL_RESID_POINTER_HSIZEBAR 10010 +#define SAL_RESID_POINTER_VSIZEBAR 10011 +#define SAL_RESID_POINTER_HAND 10012 +#define SAL_RESID_POINTER_REFHAND 10013 +#define SAL_RESID_POINTER_PEN 10014 +#define SAL_RESID_POINTER_MAGNIFY 10015 +#define SAL_RESID_POINTER_FILL 10016 +#define SAL_RESID_POINTER_ROTATE 10017 +#define SAL_RESID_POINTER_HSHEAR 10018 +#define SAL_RESID_POINTER_VSHEAR 10019 +#define SAL_RESID_POINTER_MIRROR 10020 +#define SAL_RESID_POINTER_CROOK 10021 +#define SAL_RESID_POINTER_CROP 10022 +#define SAL_RESID_POINTER_MOVEPOINT 10023 +#define SAL_RESID_POINTER_MOVEBEZIERWEIGHT 10024 +#define SAL_RESID_POINTER_MOVEDATA 10025 +#define SAL_RESID_POINTER_COPYDATA 10026 +#define SAL_RESID_POINTER_LINKDATA 10027 +#define SAL_RESID_POINTER_MOVEDATALINK 10028 +#define SAL_RESID_POINTER_COPYDATALINK 10029 +#define SAL_RESID_POINTER_MOVEFILE 10030 +#define SAL_RESID_POINTER_COPYFILE 10031 +#define SAL_RESID_POINTER_LINKFILE 10032 +#define SAL_RESID_POINTER_MOVEFILELINK 10033 +#define SAL_RESID_POINTER_COPYFILELINK 10034 +#define SAL_RESID_POINTER_MOVEFILES 10035 +#define SAL_RESID_POINTER_COPYFILES 10036 +#define SAL_RESID_POINTER_NOTALLOWED 10037 +#define SAL_RESID_POINTER_DRAW_LINE 10038 +#define SAL_RESID_POINTER_DRAW_RECT 10039 +#define SAL_RESID_POINTER_DRAW_POLYGON 10040 +#define SAL_RESID_POINTER_DRAW_BEZIER 10041 +#define SAL_RESID_POINTER_DRAW_ARC 10042 +#define SAL_RESID_POINTER_DRAW_PIE 10043 +#define SAL_RESID_POINTER_DRAW_CIRCLECUT 10044 +#define SAL_RESID_POINTER_DRAW_ELLIPSE 10045 +#define SAL_RESID_POINTER_DRAW_FREEHAND 10046 +#define SAL_RESID_POINTER_DRAW_CONNECT 10047 +#define SAL_RESID_POINTER_DRAW_TEXT 10048 +#define SAL_RESID_POINTER_DRAW_CAPTION 10049 +#define SAL_RESID_POINTER_CHART 10050 +#define SAL_RESID_POINTER_DETECTIVE 10051 +#define SAL_RESID_POINTER_PIVOT_COL 10052 +#define SAL_RESID_POINTER_PIVOT_ROW 10053 +#define SAL_RESID_POINTER_PIVOT_FIELD 10054 +#define SAL_RESID_POINTER_CHAIN 10055 +#define SAL_RESID_POINTER_CHAIN_NOTALLOWED 10056 +#define SAL_RESID_POINTER_TIMEEVENT_MOVE 10057 +#define SAL_RESID_POINTER_TIMEEVENT_SIZE 10058 +#define SAL_RESID_POINTER_AUTOSCROLL_N 10059 +#define SAL_RESID_POINTER_AUTOSCROLL_S 10060 +#define SAL_RESID_POINTER_AUTOSCROLL_W 10061 +#define SAL_RESID_POINTER_AUTOSCROLL_E 10062 +#define SAL_RESID_POINTER_AUTOSCROLL_NW 10063 +#define SAL_RESID_POINTER_AUTOSCROLL_NE 10064 +#define SAL_RESID_POINTER_AUTOSCROLL_SW 10065 +#define SAL_RESID_POINTER_AUTOSCROLL_SE 10066 +#define SAL_RESID_POINTER_AUTOSCROLL_NS 10067 +#define SAL_RESID_POINTER_AUTOSCROLL_WE 10068 +#define SAL_RESID_POINTER_AUTOSCROLL_NSWE 10069 +#define SAL_RESID_POINTER_AIRBRUSH 10070 +#define SAL_RESID_POINTER_TEXT_VERTICAL 10071 +#define SAL_RESID_POINTER_PIVOT_DELETE 10072 +#define SAL_RESID_POINTER_TAB_SELECT_S 10073 +#define SAL_RESID_POINTER_TAB_SELECT_E 10074 +#define SAL_RESID_POINTER_TAB_SELECT_SE 10075 +#define SAL_RESID_POINTER_TAB_SELECT_W 10076 +#define SAL_RESID_POINTER_TAB_SELECT_SW 10077 +#define SAL_RESID_POINTER_PAINTBRUSH 10078 + +#define SAL_RESID_BITMAP_50 11000 + +#define SAL_RESID_ICON_DEFAULT 1 + +#endif // _SV_SALIDS_HRC diff --git a/vcl/win/inc/salinst.h b/vcl/win/inc/salinst.h new file mode 100644 index 000000000000..33a1a941ed49 --- /dev/null +++ b/vcl/win/inc/salinst.h @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salinst.h,v $ + * $Revision: 1.16.154.1 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALINST_H +#define _SV_SALINST_H + +#include <vcl/sv.h> +#include <vcl/salinst.hxx> + +namespace vos { class OMutex; } + +// ------------------- +// - SalInstanceData - +// ------------------- + +class SalYieldMutex; + +class WinSalInstance : public SalInstance +{ +public: + HINSTANCE mhInst; // Instance Handle + HWND mhComWnd; // window, for communication (between threads and the main thread) + SalYieldMutex* mpSalYieldMutex; // Sal-Yield-Mutex + vos::OMutex* mpSalWaitMutex; // Sal-Wait-Mutex + USHORT mnYieldWaitCount; // Wait-Count +public: + WinSalInstance(); + virtual ~WinSalInstance(); + + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, ULONG nStyle ); + virtual SalFrame* CreateFrame( SalFrame* pParent, ULONG nStyle ); + virtual void DestroyFrame( SalFrame* pFrame ); + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow = TRUE ); + virtual void DestroyObject( SalObject* pObject ); + virtual SalVirtualDevice* CreateVirtualDevice( SalGraphics* pGraphics, + long nDX, long nDY, + USHORT nBitCount, const SystemGraphicsData *pData ); + virtual void DestroyVirtualDevice( SalVirtualDevice* pDevice ); + + virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ); + virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ); + virtual SalPrinter* CreatePrinter( SalInfoPrinter* pInfoPrinter ); + virtual void DestroyPrinter( SalPrinter* pPrinter ); + virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ); + virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ); + virtual void DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ); + virtual String GetDefaultPrinter(); + virtual SalTimer* CreateSalTimer(); + virtual SalI18NImeStatus* CreateI18NImeStatus(); + virtual SalSystem* CreateSalSystem(); + virtual SalBitmap* CreateSalBitmap(); + virtual vos::IMutex* GetYieldMutex(); + virtual ULONG ReleaseYieldMutex(); + virtual void AcquireYieldMutex( ULONG nCount ); + virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ); + virtual bool AnyInput( USHORT nType ); + virtual SalMenu* CreateMenu( BOOL bMenuBar ); + virtual void DestroyMenu( SalMenu* ); + virtual SalMenuItem* CreateMenuItem( const SalItemParams* pItemData ); + virtual void DestroyMenuItem( SalMenuItem* ); + virtual SalSession* CreateSalSession(); + virtual void* GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ); + virtual void AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType); + + static int WorkaroundExceptionHandlingInUSER32Lib(int nExcept, LPEXCEPTION_POINTERS pExceptionInfo); +}; + +// -------------- +// - Prototypen - +// -------------- + +SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, HWND hWndParent, ULONG nSalFrameStyle ); +SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent ); +HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, BOOL bAsChild ); +void ImplSalStartTimer( ULONG nMS, BOOL bMutex = FALSE ); +void ImplSalPrinterAbortJobAsync( HDC hPrnDC ); + +#endif // _SV_SALINST_H diff --git a/vcl/win/inc/salmenu.h b/vcl/win/inc/salmenu.h new file mode 100644 index 000000000000..5dd01d3810d4 --- /dev/null +++ b/vcl/win/inc/salmenu.h @@ -0,0 +1,81 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salmenu.h,v $ + * $Revision: 1.7 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALMENU_H +#define _SV_SALMENU_H + +#include <vcl/sv.h> +#include <vcl/bitmap.hxx> +#include <vcl/salmenu.hxx> + + +class WinSalMenu : public SalMenu +{ +public: + WinSalMenu(); + virtual ~WinSalMenu(); + virtual BOOL VisibleMenuBar(); // must return TRUE to actually DISPLAY native menu bars + // otherwise only menu messages are processed (eg, OLE on Windows) + + virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ); + virtual void RemoveItem( unsigned nPos ); + virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ); + virtual void SetFrame( const SalFrame* pFrame ); + virtual void CheckItem( unsigned nPos, BOOL bCheck ); + virtual void EnableItem( unsigned nPos, BOOL bEnable ); + virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText ); + virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage ); + virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const XubString& rKeyName ); + virtual void GetSystemMenuData( SystemMenuData* pData ); + + HMENU mhMenu; // the menu handle + BOOL mbMenuBar; // true for menu bars + HWND mhWnd; // the window handle where the menubar is attached, may be NULL + WinSalMenu *mpParentMenu; // the parent menu +}; + +class WinSalMenuItem : public SalMenuItem +{ +public: + WinSalMenuItem(); + virtual ~WinSalMenuItem(); + + + MENUITEMINFOW mInfo; + void* mpMenu; // pointer to corresponding VCL menu + XubString mText; // the item text + XubString mAccelText; // the accelerator string + Bitmap maBitmap; // item image + int mnId; // item id + WinSalMenu* mpSalMenu; // the menu where this item is inserted +}; + +#endif // _SV_SALMENU_H + diff --git a/vcl/win/inc/salnativewidgets.h b/vcl/win/inc/salnativewidgets.h new file mode 100644 index 000000000000..8f30092056e6 --- /dev/null +++ b/vcl/win/inc/salnativewidgets.h @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salnativewidgets.h,v $ + * $Revision: 1.5 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_NATIVEWIDGETS_H +#define _SV_NATIVEWIDGETS_H + + +#ifdef __cplusplus + +#include <vcl/sv.h> + +/* SalControlHandleData: + * + * Holds platform specific theming data. + */ + +class SalControlHandleData +{ + public: + SalControlHandleData( void ); + ~SalControlHandleData( void ); + + public: + // nothing needed on Win32 +}; + + +#endif /* __cplusplus */ + +#endif diff --git a/vcl/win/inc/salobj.h b/vcl/win/inc/salobj.h new file mode 100644 index 000000000000..f903a7ac89e9 --- /dev/null +++ b/vcl/win/inc/salobj.h @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salobj.h,v $ + * $Revision: 1.5 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALOBJ_H +#define _SV_SALOBJ_H + +#include <vcl/sv.h> +#include <vcl/salobj.hxx> + +// ----------------- +// - SalObjectData - +// ----------------- + +class WinSalObject : public SalObject +{ +public: + HWND mhWnd; // Window handle + HWND mhWndChild; // Child Window handle + HWND mhLastFocusWnd; // Child-Window, welches als letztes den Focus hatte + SystemChildData maSysData; // SystemEnvData + RGNDATA* mpClipRgnData; // ClipRegion-Data + RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data + RECT* mpNextClipRect; // Naechstes ClipRegion-Rect + BOOL mbFirstClipRect; // Flag for first cliprect to insert + WinSalObject* mpNextObject; // pointer to next object + + + WinSalObject(); + virtual ~WinSalObject(); + + virtual void ResetClipRegion(); + virtual USHORT GetClipRegionType(); + virtual void BeginSetClipRegion( ULONG nRects ); + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ); + virtual void EndSetClipRegion(); + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ); + virtual void Show( BOOL bVisible ); + virtual void Enable( BOOL nEnable ); + virtual void GrabFocus(); + virtual void SetBackground(); + virtual void SetBackground( SalColor nSalColor ); + virtual const SystemEnvData* GetSystemData() const; +}; + +#endif // _SV_SALOBJ_H diff --git a/vcl/win/inc/salprn.h b/vcl/win/inc/salprn.h new file mode 100644 index 000000000000..58d721fd043a --- /dev/null +++ b/vcl/win/inc/salprn.h @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salprn.h,v $ + * $Revision: 1.9 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALPRN_H +#define _SV_SALPRN_H + +#include <vcl/sv.h> +#include <vcl/salprn.hxx> + +// ----------------- +// - SalDriverData - +// ----------------- + +// WNT3 +#define SAL_DRIVERDATA_SYSSIGN ((ULONG)0x574E5433) +#define SAL_DRIVERDATA_VERSION_A 1 +#define SAL_DRIVERDATA_VERSION_W 2 + +#pragma pack( 1 ) + +struct SalDriverData +{ + ULONG mnSysSignature; + USHORT mnVersion; + USHORT mnDriverOffset; + BYTE maDriverData[1]; +}; + +#pragma pack() + +// --------------------- +// - WinSalInfoPrinter - +// --------------------- + +class WinSalGraphics; + +class WinSalInfoPrinter : public SalInfoPrinter +{ +public: + WinSalGraphics* mpGraphics; // current Printer graphics + XubString maDriverName; // printer driver name + XubString maDeviceName; // printer device name + XubString maPortName; // printer port name + HDC mhDC; // printer hdc + BOOL mbGraphics; // is Graphics used +public: + WinSalInfoPrinter(); + virtual ~WinSalInfoPrinter(); + + virtual SalGraphics* GetGraphics(); + virtual void ReleaseGraphics( SalGraphics* pGraphics ); + virtual BOOL Setup( SalFrame* pFrame, ImplJobSetup* pSetupData ); + virtual BOOL SetPrinterData( ImplJobSetup* pSetupData ); + virtual BOOL SetData( ULONG nFlags, ImplJobSetup* pSetupData ); + virtual void GetPageInfo( const ImplJobSetup* pSetupData, + long& rOutWidth, long& rOutHeight, + long& rPageOffX, long& rPageOffY, + long& rPageWidth, long& rPageHeight ); + virtual ULONG GetCapabilities( const ImplJobSetup* pSetupData, USHORT nType ); + virtual ULONG GetPaperBinCount( const ImplJobSetup* pSetupData ); + virtual String GetPaperBinName( const ImplJobSetup* pSetupData, ULONG nPaperBin ); + virtual void InitPaperFormats( const ImplJobSetup* pSetupData ); + virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ); + virtual DuplexMode GetDuplexMode( const ImplJobSetup* pSetupData ); +}; + +// ----------------- +// - WinSalPrinter - +// ----------------- + +class WinSalPrinter : public SalPrinter +{ +public: + WinSalGraphics* mpGraphics; // current Printer graphics + WinSalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter + WinSalPrinter* mpNextPrinter; // next printing printer + HDC mhDC; // printer hdc + ULONG mnError; // Error Code + ULONG mnCopies; // Kopien + BOOL mbCollate; // Sortierte Kopien + BOOL mbAbort; // Job Aborted + + bool mbValid; + +public: + WinSalPrinter(); + virtual ~WinSalPrinter(); + + using SalPrinter::StartJob; + virtual BOOL StartJob( const XubString* pFileName, + const XubString& rJobName, + const XubString& rAppName, + ULONG nCopies, BOOL bCollate, + ImplJobSetup* pSetupData ); + virtual BOOL EndJob(); + virtual BOOL AbortJob(); + virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, BOOL bNewJobData ); + virtual BOOL EndPage(); + virtual ULONG GetErrorCode(); + + void markInvalid(); + bool isValid() const { return mbValid; } +}; + +#endif // _SV_SALPRN_H diff --git a/vcl/win/inc/salsys.h b/vcl/win/inc/salsys.h new file mode 100644 index 000000000000..3bd82c8e1d53 --- /dev/null +++ b/vcl/win/inc/salsys.h @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salsys.h,v $ + * $Revision: 1.6 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALSYS_H +#define _SV_SALSYS_H + +#include <vcl/salsys.hxx> + +#include <vector> +#include <map> + +class WinSalSystem : public SalSystem +{ + public: + struct DisplayMonitor + { + rtl::OUString m_aName; + rtl::OUString m_aDeviceName; + Rectangle m_aArea; + Rectangle m_aWorkArea; + sal_Int32 m_nStateFlags; + + DisplayMonitor() : m_nStateFlags( 0 ) {} + DisplayMonitor( const rtl::OUString& rName, + const rtl::OUString& rDevName, + const Rectangle& rArea, + const Rectangle& rWorkArea, + DWORD nStateFlags ) + : m_aName( rName ), + m_aDeviceName( rDevName ), + m_aArea( rArea ), + m_aWorkArea( rWorkArea ), + m_nStateFlags( nStateFlags ) + { + } + ~DisplayMonitor() {} + }; + private: + std::vector<DisplayMonitor> m_aMonitors; + std::map<rtl::OUString, unsigned int> m_aDeviceNameToMonitor; + unsigned int m_nPrimary; +public: + WinSalSystem() : m_nPrimary( 0 ) {} + virtual ~WinSalSystem(); + + virtual unsigned int GetDisplayScreenCount(); + virtual bool IsMultiDisplay(); + virtual unsigned int GetDefaultDisplayNumber(); + virtual Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ); + virtual Rectangle GetDisplayWorkAreaPosSizePixel( unsigned int nScreen ); + virtual rtl::OUString GetScreenName( unsigned int nScreen ); + virtual int ShowNativeMessageBox( const String& rTitle, + const String& rMessage, + int nButtonCombination, + int nDefaultButton); + bool initMonitors(); + // discards monitorinfo; used by WM_DISPLAYCHANGED handler + void clearMonitors(); + const std::vector<DisplayMonitor>& getMonitors() + { initMonitors(); return m_aMonitors;} + + BOOL handleMonitorCallback( sal_IntPtr /*HMONITOR*/, + sal_IntPtr /*HDC*/, + sal_IntPtr /*LPRECT*/ ); +}; + +#endif // _SV_SALSYS_H + diff --git a/vcl/win/inc/saltimer.h b/vcl/win/inc/saltimer.h new file mode 100644 index 000000000000..461aa15cce22 --- /dev/null +++ b/vcl/win/inc/saltimer.h @@ -0,0 +1,47 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: saltimer.h,v $ + * $Revision: 1.7 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALTIMER_H +#define _SV_SALTIMER_H + +#include <vcl/saltimer.hxx> + +class WinSalTimer : public SalTimer +{ +public: + WinSalTimer() {} + virtual ~WinSalTimer(); + + // overload all pure virtual methods + void Start( ULONG nMS ); + void Stop(); +}; + +#endif diff --git a/vcl/win/inc/salvd.h b/vcl/win/inc/salvd.h new file mode 100644 index 000000000000..ce78e7bbe3bb --- /dev/null +++ b/vcl/win/inc/salvd.h @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salvd.h,v $ + * $Revision: 1.7 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SALVD_H +#define _SV_SALVD_H + +#include <vcl/sv.h> +#include <vcl/salvd.hxx> + +class WinSalGraphics; + +// ----------------- +// - SalVirDevData - +// ----------------- + +class WinSalVirtualDevice : public SalVirtualDevice +{ +public: + HDC mhDC; // HDC or 0 for Cache Device + HBITMAP mhBmp; // Memory Bitmap + HBITMAP mhDefBmp; // Default Bitmap + WinSalGraphics* mpGraphics; // current VirDev graphics + WinSalVirtualDevice* mpNext; // next VirDev + USHORT mnBitCount; // BitCount (0 or 1) + BOOL mbGraphics; // is Graphics used + BOOL mbForeignDC; // uses a foreign DC instead of a bitmap + + WinSalVirtualDevice(); + virtual ~WinSalVirtualDevice(); + + virtual SalGraphics* GetGraphics(); + virtual void ReleaseGraphics( SalGraphics* pGraphics ); + virtual BOOL SetSize( long nNewDX, long nNewDY ); + virtual void GetSize( long& rWidth, long& rHeight ); +}; + +#endif // _SV_SALVD_H diff --git a/vcl/win/inc/svsys.h b/vcl/win/inc/svsys.h new file mode 100644 index 000000000000..7a96bafe917d --- /dev/null +++ b/vcl/win/inc/svsys.h @@ -0,0 +1,36 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svsys.h,v $ + * $Revision: 1.3 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_SVSYS_H +#define _SV_SVSYS_H + +#include <tools/svwin.h> + +#endif // _SV_SVSYS_H diff --git a/vcl/win/inc/wincomp.hxx b/vcl/win/inc/wincomp.hxx new file mode 100644 index 000000000000..089fd9f9fb1f --- /dev/null +++ b/vcl/win/inc/wincomp.hxx @@ -0,0 +1,267 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: wincomp.hxx,v $ + * $Revision: 1.5 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SV_WINCOMP_HXX +#define _SV_WINCOMP_HXX + +#ifndef _STRING_H +#include <string.h> +#endif +#include <vcl/sv.h> + +// ---------- +// - Strict - +// ---------- + +// Anpassungen fuer TypeChecking + +inline HPEN SelectPen( HDC hDC, HPEN hPen ) +{ + return (HPEN)SelectObject( hDC, (HGDIOBJ)hPen ); +} + +inline void DeletePen( HPEN hPen ) +{ + DeleteObject( (HGDIOBJ)hPen ); +} + +inline HPEN GetStockPen( int nObject ) +{ + return (HPEN)GetStockObject( nObject ); +} + +inline HBRUSH SelectBrush( HDC hDC, HBRUSH hBrush ) +{ + return (HBRUSH)SelectObject( hDC, (HGDIOBJ)hBrush ); +} + +inline void DeleteBrush( HBRUSH hBrush ) +{ + DeleteObject( (HGDIOBJ)hBrush ); +} + +inline HBRUSH GetStockBrush( int nObject ) +{ + return (HBRUSH)GetStockObject( nObject ); +} + +inline HFONT SelectFont( HDC hDC, HFONT hFont ) +{ + return (HFONT)SelectObject( hDC, (HGDIOBJ)hFont ); +} + +inline void DeleteFont( HFONT hFont ) +{ + DeleteObject( (HGDIOBJ)hFont ); +} + +inline HFONT GetStockFont( int nObject ) +{ + return (HFONT)GetStockObject( nObject ); +} + +inline HBITMAP SelectBitmap( HDC hDC, HBITMAP hBitmap ) +{ + return (HBITMAP)SelectObject( hDC, (HGDIOBJ)hBitmap ); +} + +inline void DeleteBitmap( HBITMAP hBitmap ) +{ + DeleteObject( (HGDIOBJ)hBitmap ); +} + +inline void DeleteRegion( HRGN hRegion ) +{ + DeleteObject( (HGDIOBJ)hRegion ); +} + +inline HPALETTE GetStockPalette( int nObject ) +{ + return (HPALETTE)GetStockObject( nObject ); +} + +inline void DeletePalette( HPALETTE hPalette ) +{ + DeleteObject( (HGDIOBJ)hPalette ); +} + +inline void SetWindowStyle( HWND hWnd, DWORD nStyle ) +{ + SetWindowLong( hWnd, GWL_STYLE, nStyle ); +} + +inline DWORD GetWindowStyle( HWND hWnd ) +{ + return GetWindowLong( hWnd, GWL_STYLE ); +} + +inline void SetWindowExStyle( HWND hWnd, DWORD nStyle ) +{ + SetWindowLong( hWnd, GWL_EXSTYLE, nStyle ); +} + +inline DWORD GetWindowExStyle( HWND hWnd ) +{ + return GetWindowLong( hWnd, GWL_EXSTYLE ); +} + +inline WIN_BOOL IsMinimized( HWND hWnd ) +{ + return IsIconic( hWnd ); +} + +inline WIN_BOOL IsMaximized( HWND hWnd ) +{ + return IsZoomed( hWnd ); +} + +inline void SetWindowFont( HWND hWnd, HFONT hFont, WIN_BOOL bRedraw ) +{ + SendMessage( hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM((UINT)bRedraw,0) ); +} + +inline HFONT GetWindowFont( HWND hWnd ) +{ + return (HFONT)(UINT)SendMessage( hWnd, WM_GETFONT, 0, 0 ); +} + +inline void SetClassCursor( HWND hWnd, HCURSOR hCursor ) +{ + SetClassLong( hWnd, GCL_HCURSOR, (DWORD)hCursor ); +} + +inline HCURSOR GetClassCursor( HWND hWnd ) +{ + return (HCURSOR)GetClassLong( hWnd, GCL_HCURSOR ); +} + +inline void SetClassIcon( HWND hWnd, HICON hIcon ) +{ + SetClassLong( hWnd, GCL_HICON, (DWORD)hIcon ); +} + +inline HICON GetClassIcon( HWND hWnd ) +{ + return (HICON)GetClassLong( hWnd, GCL_HICON ); +} + +inline HBRUSH SetClassBrush( HWND hWnd, HBRUSH hBrush ) +{ + return (HBRUSH)SetClassLong( hWnd, GCL_HBRBACKGROUND, (DWORD)hBrush ); +} + +inline HBRUSH GetClassBrush( HWND hWnd ) +{ + return (HBRUSH)GetClassLong( hWnd, GCL_HBRBACKGROUND ); +} + +inline HINSTANCE GetWindowInstance( HWND hWnd ) +{ + return (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ); +} + +// ------------------------ +// - ZMouse Erweiterungen - +// ------------------------ + +#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" + +#define MOUSEZ_CLASSNAME "MouseZ" // wheel window class +#define MOUSEZ_TITLE "Magellan MSWHEEL" // wheel window title + +#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME) +#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE) + +#define MSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG" + +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 +#endif +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif +#ifndef SPI_GETWHEELSCROLLLINES +#define SPI_GETWHEELSCROLLLINES 104 +#endif +#ifndef SPI_SETWHEELSCROLLLINES +#define SPI_SETWHEELSCROLLLINES 105 +#endif +#ifndef WHEEL_PAGESCROLL +#define WHEEL_PAGESCROLL (UINT_MAX) +#endif + + +// ----------------------------- +// - SystemAgent Erweiterungen - +// ----------------------------- + +#define ENABLE_AGENT 1 +#define DISABLE_AGENT 2 +#define GET_AGENT_STATUS 3 +typedef int (APIENTRY* SysAgt_Enable_PROC)( int ); + +// --------------------- +// - 5.0-Erweiterungen - +// --------------------- + +#ifndef COLOR_GRADIENTACTIVECAPTION +#define COLOR_GRADIENTACTIVECAPTION 27 +#endif +#ifndef COLOR_GRADIENTINACTIVECAPTION +#define COLOR_GRADIENTINACTIVECAPTION 28 +#endif + +#ifndef SPI_GETFLATMENU +#define SPI_GETFLATMENU 0x1022 +#endif +#ifndef COLOR_MENUBAR +#define COLOR_MENUBAR 30 +#endif +#ifndef COLOR_MENUHILIGHT +#define COLOR_MENUHILIGHT 29 +#endif + +#ifndef CS_DROPSHADOW +#define CS_DROPSHADOW 0x00020000 +#endif + +// ------------------------------------------------------- +// MT 12/03: From winuser.h, only needed in salframe.cxx +// Better change salframe.cxx to include winuser.h +// ------------------------------------------------------- + +#define WS_EX_LAYERED 0x00080000 + +#ifndef WM_UNICHAR +#define WM_UNICHAR 0x0109 +#define UNICODE_NOCHAR 0xFFFF +#endif + +#endif // _SV_WINCOMP_HXX diff --git a/vcl/win/source/app/MAKEFILE.MK b/vcl/win/source/app/MAKEFILE.MK new file mode 100644 index 000000000000..83339dbb997a --- /dev/null +++ b/vcl/win/source/app/MAKEFILE.MK @@ -0,0 +1,57 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: MAKEFILE.MK,v $ +# +# $Revision: 1.11 $ +# +# 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. +# +#************************************************************************* + + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=salapp +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- #105371# +CFLAGS += -DWINVER=0x0400 + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/salshl.obj \ + $(SLO)$/saldata.obj \ + $(SLO)$/salinst.obj \ + $(SLO)$/saltimer.obj \ + $(SLO)$/salinfo.obj + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/win/source/app/saldata.cxx b/vcl/win/source/app/saldata.cxx new file mode 100644 index 000000000000..c9009492a4af --- /dev/null +++ b/vcl/win/source/app/saldata.cxx @@ -0,0 +1,193 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: saldata.cxx,v $ + * $Revision: 1.9 $ + * + * 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 <saldata.hxx> +#include <vcl/svapp.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, 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 ) +{ + if ( aSalShlData.mbWNT ) + return SetWindowLongW( hWnd, nIndex, dwNewLong ); + else + return SetWindowLongA( hWnd, nIndex, dwNewLong ); +} + +// ----------------------------------------------------------------------- + +LONG ImplGetWindowLong( HWND hWnd, int nIndex ) +{ + if ( aSalShlData.mbWNT ) + return GetWindowLongW( hWnd, nIndex ); + else + return GetWindowLongA( hWnd, nIndex ); +} + +// ----------------------------------------------------------------------- + +WIN_BOOL ImplPostMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + if ( aSalShlData.mbWNT ) + return PostMessageW( hWnd, nMsg, wParam, lParam ); + else + return PostMessageA( hWnd, nMsg, wParam, lParam ); +} + +// ----------------------------------------------------------------------- + +WIN_BOOL ImplSendMessage( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) +{ + WIN_BOOL bRet; + if ( aSalShlData.mbWNT ) + bRet = SendMessageW( hWnd, nMsg, wParam, lParam ); + else + bRet = SendMessageA( hWnd, nMsg, wParam, lParam ); + + return bRet; +} + +// ----------------------------------------------------------------------- + +WIN_BOOL ImplGetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ) +{ + if ( aSalShlData.mbWNT ) + return GetMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax ); + else + return GetMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax ); +} + +// ----------------------------------------------------------------------- + +WIN_BOOL ImplPeekMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg ) +{ + if ( aSalShlData.mbWNT ) + return PeekMessageW( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg ); + else + return PeekMessageA( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg ); +} + +// ----------------------------------------------------------------------- + +LONG ImplDispatchMessage( CONST MSG *lpMsg ) +{ + if ( aSalShlData.mbWNT ) + return DispatchMessageW( lpMsg ); + else + return DispatchMessageA( lpMsg ); +} + diff --git a/vcl/win/source/app/salinfo.cxx b/vcl/win/source/app/salinfo.cxx new file mode 100644 index 000000000000..cc5a89097d9f --- /dev/null +++ b/vcl/win/source/app/salinfo.cxx @@ -0,0 +1,303 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salinfo.cxx,v $ + * $Revision: 1.18 $ + * + * 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 + +#define VCL_NEED_BASETSD +#include "tools/presys.h" +#if defined _MSC_VER +#pragma warning(push, 1) +#endif +#include <windows.h> +#include <winuser.h> +#if defined _MSC_VER +#pragma warning(pop) +#endif +#include "tools/postsys.h" + +#include "tools/string.hxx" +#include "salsys.h" +#include "salframe.h" +#include "salinst.h" +#include "saldata.hxx" +#include "tools/debug.hxx" +#include "vcl/svdata.hxx" +#include "vcl/window.hxx" + +#include "rtl/ustrbuf.hxx" + +#include <hash_map> + +SalSystem* WinSalInstance::CreateSalSystem() +{ + return new WinSalSystem(); +} + +WinSalSystem::~WinSalSystem() +{ +} + +// ----------------------------------------------------------------------- + +static WIN_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) ); +} + +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 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_MIRRORING_DRIVER) == 0 ) // sort out non 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 100644 index 000000000000..2b5ac6d3162d --- /dev/null +++ b/vcl/win/source/app/salinst.cxx @@ -0,0 +1,1173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salinst.cxx,v $ + * $Revision: 1.42.154.1 $ + * + * 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/debug.hxx> +#include <wincomp.hxx> +#include <salids.hrc> +#include <saldata.hxx> +#include <salinst.h> +#include <salframe.h> +#include <salobj.h> +#include <vcl/salsys.hxx> +#include <saltimer.h> +#include <vcl/salatype.hxx> +#include <salbmp.h> +#include <vcl/salimestatus.hxx> +#include <vcl/timer.hxx> +#include <wincomp.hxx> // CS_DROPSHADOW + +#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; + ULONG mnCount; + DWORD mnThreadId; + +public: + SalYieldMutex( WinSalInstance* pInstData ); + + virtual void SAL_CALL acquire(); + virtual void SAL_CALL release(); + virtual sal_Bool SAL_CALL tryToAcquire(); + + ULONG GetAcquireCount( 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; +} + +// ----------------------------------------------------------------------- + +ULONG SalYieldMutex::GetAcquireCount( 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 + 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(); +} + +// ----------------------------------------------------------------------- + +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(); + } +} + +// ----------------------------------------------------------------------- + +ULONG ImplSalReleaseYieldMutex() +{ + WinSalInstance* pInst = GetSalData()->mpFirstInstance; + if ( !pInst ) + return 0; + + SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex; + ULONG nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() ); + ULONG n = nCount; + while ( n ) + { + pYieldMutex->release(); + n--; + } + + return nCount; +} + +// ----------------------------------------------------------------------- + +void ImplSalAcquireYieldMutex( ULONG nCount ) +{ + WinSalInstance* pInst = GetSalData()->mpFirstInstance; + if ( !pInst ) + return; + + SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex; + while ( nCount ) + { + pYieldMutex->acquire(); + nCount--; + } +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL + +void ImplDbgTestSolarMutex() +{ + SalData* pSalData = GetSalData(); + DWORD nCurThreadId = GetCurrentThreadId(); + if ( pSalData->mnAppThreadId != nCurThreadId ) + { + if ( pSalData->mpFirstInstance ) + { + SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex; + if ( pYieldMutex->mnThreadId != nCurThreadId ) + { + DBG_ERROR( "SolarMutex not locked, and not thread save code in VCL is called from outside of the main thread" ); + } + } + } + else + { + if ( pSalData->mpFirstInstance ) + { + SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex; + if ( pYieldMutex->mnThreadId != nCurThreadId ) + { + DBG_ERROR( "SolarMutex not locked in the main thread" ); + } + } + } +} + +#endif + +// ======================================================================= + +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 + + // init with NULL + gdiplusToken = 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.mbWNT = 0; + 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 ) + { + aSalShlData.mbWNT = 1; + // 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 ) + { + if ( aSalShlData.mbWNT ) + { + 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; + } + else + { + WNDCLASSEXA aWndClassEx; + aWndClassEx.cbSize = sizeof( aWndClassEx ); + aWndClassEx.style = CS_OWNDC; + aWndClassEx.lpfnWndProc = SalFrameWndProcA; + 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_CLASSNAMEA; + ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm ); + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + + aWndClassEx.hIcon = 0; + aWndClassEx.hIconSm = 0; + aWndClassEx.style |= CS_SAVEBITS; + aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEA; + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + + aWndClassEx.style = 0; + aWndClassEx.lpfnWndProc = SalComWndProcA; + aWndClassEx.cbWndExtra = 0; + aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEA; + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + } + } + + HWND hComWnd; + if ( aSalShlData.mbWNT ) + { + hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW, + L"", WS_POPUP, 0, 0, 0, 0, 0, 0, + pSalData->mhInst, NULL ); + } + else + { + hComWnd = CreateWindowExA( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEA, + "", 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(); +} + +// ----------------------------------------------------------------------- + +WinSalInstance::~WinSalInstance() +{ + mpSalYieldMutex->release(); + delete mpSalYieldMutex; + delete mpSalWaitMutex; + DestroyWindow( mhComWnd ); +} + +// ----------------------------------------------------------------------- + +vos::IMutex* WinSalInstance::GetYieldMutex() +{ + return mpSalYieldMutex; +} + +// ----------------------------------------------------------------------- + +ULONG WinSalInstance::ReleaseYieldMutex() +{ + return ImplSalReleaseYieldMutex(); +} + +// ----------------------------------------------------------------------- + +void WinSalInstance::AcquireYieldMutex( 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( BOOL bWait, BOOL bHandleAllCurrentEvents ) +{ + MSG aMsg; + bool bWasMsg = false, bOneEvent = false; + + int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; + do + { + if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &aMsg ); + ImplSalDispatchMessage( &aMsg ); + bOneEvent = bWasMsg = true; + } + else + bOneEvent = false; + } while( --nMaxEvents && bOneEvent ); + + if ( bWait && ! bWasMsg ) + { + if ( ImplGetMessage( &aMsg, 0, 0, 0 ) ) + { + TranslateMessage( &aMsg ); + ImplSalDispatchMessage( &aMsg ); + } + } +} + +// ----------------------------------------------------------------------- + +void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) +{ + SalYieldMutex* pYieldMutex = mpSalYieldMutex; + SalData* pSalData = GetSalData(); + DWORD nCurThreadId = GetCurrentThreadId(); + ULONG nCount = pYieldMutex->GetAcquireCount( nCurThreadId ); + 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( (BOOL)wParam, (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( (ULONG) lParam, FALSE ); + rDef = FALSE; + break; + case SAL_MSG_CREATEFRAME: + nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (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( USHORT 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( 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, ULONG nSalFrameStyle ) +{ + // Um auf Main-Thread umzuschalten + return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd ); +} + +// ----------------------------------------------------------------------- + +SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, 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 + 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 100644 index 000000000000..5fe804dfc0c5 --- /dev/null +++ b/vcl/win/source/app/salshl.cxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salshl.cxx,v $ + * $Revision: 1.8 $ + * + * 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 <saldata.hxx> +#include <tools/debug.hxx> + +// ======================================================================= + +SalShlData aSalShlData; + +// ======================================================================= + +#ifdef WNT + +extern "C" +{ + +#ifdef __MINGW32__ +BOOL WINAPI DllMain( HINSTANCE hInst, DWORD nReason, LPVOID pReserved ) +#else +#ifdef ICC +int _CRT_init(void); +#else +WIN_BOOL WINAPI _CRT_INIT( HINSTANCE hInst, DWORD nReason, LPVOID pReserved ); +#endif + +WIN_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; +} + +// ----------------------------------------------------------------------- + +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 100644 index 000000000000..821a6186b985 --- /dev/null +++ b/vcl/win/source/app/saltimer.cxx @@ -0,0 +1,157 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: saltimer.cxx,v $ + * $Revision: 1.12 $ + * + * 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 <saldata.hxx> +#include <saltimer.h> +#include <salinst.h> + +// ======================================================================= + +// Maximale Periode +#define MAX_SYSPERIOD 65533 + +// ======================================================================= + +void ImplSalStartTimer( ULONG nMS, 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 USHORT 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( 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/MAKEFILE.MK b/vcl/win/source/gdi/MAKEFILE.MK new file mode 100644 index 000000000000..3d8fd904b35b --- /dev/null +++ b/vcl/win/source/gdi/MAKEFILE.MK @@ -0,0 +1,73 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: MAKEFILE.MK,v $ +# +# $Revision: 1.13.152.1 $ +# +# 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. +# +#************************************************************************* + + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=salgdi + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- #105371# +.IF "$(COM)"=="GCC" +.ELSE +CFLAGS += -DWINVER=0x0400 +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES= $(SLO)$/salgdi.obj \ + $(SLO)$/salgdi2.obj \ + $(SLO)$/salgdi3.obj \ + $(SLO)$/salgdi_gdiplus.obj \ + $(SLO)$/salvd.obj \ + $(SLO)$/salprn.obj \ + $(SLO)$/salbmp.obj \ + $(SLO)$/winlayout.obj \ + $(SLO)$/wntgdi.obj \ + $(SLO)$/salnativewidgets-luna.obj + + +EXCEPTIONSFILES= $(SLO)$/salprn.obj + +.IF "$(ENABLE_GRAPHITE)" == "TRUE" +CFLAGS+=-DENABLE_GRAPHITE +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/win/source/gdi/salbmp.cxx b/vcl/win/source/gdi/salbmp.cxx new file mode 100644 index 000000000000..e4b928ca1a0d --- /dev/null +++ b/vcl/win/source/gdi/salbmp.cxx @@ -0,0 +1,635 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salbmp.cxx,v $ + * $Revision: 1.13 $ + * + * 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 <wincomp.hxx> +#include <vcl/salbtype.hxx> +#include <salgdi.h> +#include <saldata.hxx> +#include <salbmp.h> +#include <vcl/bitmap.hxx> // for BitmapSystemData +#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, USHORT 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, USHORT 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; +} + +// ------------------------------------------------------------------ + +USHORT WinSalBitmap::ImplGetDIBColorCount( HGLOBAL hDIB ) +{ + USHORT 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 = (USHORT) 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, USHORT 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 ULONG nImageSize = AlignedWidth4Bytes( nBits * rSize.Width() ) * rSize.Height(); + const USHORT 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 USHORT 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 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 USHORT nColorCount = ImplGetDIBColorCount( hNewDIB ); + const 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 = (USHORT) pBIH->biBitCount; + + if( pBuffer->mnBitCount <= 8 ) + { + const USHORT 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 ) ) + { + 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 USHORT nCount = pBuffer->maPalette.GetEntryCount(); + + memcpy( pBI->bmiColors, pBuffer->maPalette.ImplGetColorBuffer(), 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; + ULONG nWidthAl = AlignedWidth4Bytes( rSizePixel.Width() * ( bRLE4 ? 4UL : 8UL ) ); + HPBYTE pLast = pDIB + rSizePixel.Height() * nWidthAl - 1; + ULONG nCountByte; + ULONG nRunByte; + ULONG nX = 0; + 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..55caa086a57a --- /dev/null +++ b/vcl/win/source/gdi/salgdi.cxx @@ -0,0 +1,1801 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salgdi.cxx,v $ + * $Revision: 1.36 $ + * + * 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 <wincomp.hxx> +#include <saldata.hxx> +#include <salgdi.h> +#include <tools/debug.hxx> +#include <salframe.h> +#include <tools/poly.hxx> +#ifndef _RTL_STRINGBUF_HXX +#include <rtl/strbuf.hxx> +#endif + +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 ); + 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 USHORT nDitherPalCount = DITHER_PAL_COUNT; + 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 = (USHORT) 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 ( USHORT 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 ) +{ + // Default Objekte selektieren + 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( 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( ULONG nID ) +{ + SalData* pSalData = GetSalData(); + HDCCache* pC = &pSalData->mpHDCCache[ nID ]; + + if ( pC->mhActBmp ) + SelectObject( pC->mhDC, pC->mhSelBmp ); +} + +// ======================================================================= + +void ImplClearHDCCache( SalData* pData ) +{ + for( 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, + ULONG nPoly, + const ULONG* pPoints, + const SalPoint* const* pPtAry, + const BYTE* const* pFlgAry, + POINT* pWinPointAry, + BYTE* pWinFlagAry ) +{ + ULONG nCurrPoly; + for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly ) + { + const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ ); + const BYTE* pCurrFlag = *pFlgAry++; + const ULONG nCurrPoints = *pPoints++; + const bool bHaveFlagArray( pCurrFlag ); + 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, ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ + if( nPoints ) + { + USHORT 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; +} + +// ----------------------------------------------------------------------- + +USHORT WinSalGraphics::GetBitCount() +{ + return (USHORT)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 ); +} + +// ----------------------------------------------------------------------- + +void WinSalGraphics::BeginSetClipRegion( ULONG nRectCount ) +{ + if ( mhRegion ) + { + DeleteRegion( mhRegion ); + mhRegion = 0; + } + + 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; +} + + +// ----------------------------------------------------------------------- + +BOOL WinSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight ) +{ + if ( nWidth && 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++; + } + else + { + mpClipRgnData->rdh.nCount--; + mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +bool WinSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& ) +{ + // TODO: implement and advertise OutDevSupport_B2DClip support + return false; +} + +// ----------------------------------------------------------------------- + +void WinSalGraphics::EndSetClipRegion() +{ + // 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 + { + 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; + } + + SelectClipRgn( mhDC, mhRegion ); +} + +// ----------------------------------------------------------------------- + +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; + BOOL bStockPen = FALSE; + + // search for stock pen (only screen, because printer have problems, + // when we use stock objects) + if ( !mbPrinter ) + { + SalData* pSalData = GetSalData(); + for ( USHORT 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; + BOOL bStockBrush = FALSE; + + // search for stock brush (only screen, because printer have problems, + // when we use stock objects) + if ( !mbPrinter ) + { + for ( USHORT 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( 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( 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( 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( 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" ); + + ULONG nCurrPoly, nTotalPoints; + const 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, ULONG nComp, ULONG nSize ) +{ + while ( nComp-- >= nSize ) + { + 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 BOOL ImplGetBoundingBox( double* nNumb, BYTE* pSource, ULONG nSize ) +{ + 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; + BOOL bDivision = FALSE; + BOOL bNegative = FALSE; + BOOL bValid = TRUE; + + while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++; + BYTE nByte = *pDest; + while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) ) + { + switch ( nByte ) + { + case '.' : + if ( bDivision ) + bValid = FALSE; + else + bDivision = TRUE; + break; + case '-' : + bNegative = TRUE; + break; + default : + if ( ( nByte < '0' ) || ( nByte > '9' ) ) + nSizeLeft = 1; // error parsing the bounding box values + else if ( bValid ) + { + if ( bDivision ) + nDivision*=10; + nNumb[i] *= 10; + nNumb[i] += nByte - '0'; + } + break; + } + nSizeLeft--; + nByte = *(++pDest); + } + if ( bNegative ) + nNumb[i] = -nNumb[i]; + if ( bDivision && ( nDivision != 1 ) ) + nNumb[i] /= nDivision; + } + if ( i == 4 ) + bRetValue = TRUE; + } + return bRetValue; +} + +BOOL WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize ) +{ + 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 USHORT + 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 + // ---------------------------------------------------------------------------------- + *((USHORT*)aBuf.getStr()) = (USHORT)( 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 USHORT 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" ); + *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 ); + Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 ); + + + // #107797# Write out actual EPS content + // ---------------------------------------------------------------------------------- + ULONG nToDo = nSize; + 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 + *((USHORT*)aBuf.getStr()) = (USHORT)nDoNow; + memcpy( (void*)(aBuf.getStr() + 2), (BYTE*)pPtr + nSize - nToDo, nDoNow ); + ULONG nResult = Escape ( mhDC, nEscape, nDoNow + 2, (LPTSTR)aBuf.getStr(), 0 ); + if (!nResult ) + break; + nToDo -= nResult; + } + + + // #107797# Write out EPS encapsulation footer + // ---------------------------------------------------------------------------------- + // reserve a USHORT 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" ); + *((USHORT*)aBuf.getStr()) = (USHORT)( 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..0a60c6971213 --- /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 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salgdi2.cxx,v $ + * $Revision: 1.15 $ + * + * 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 <wincomp.hxx> +#include <salbmp.h> +#include <saldata.hxx> +#ifndef _SV_SALIDS_HRC +#include <salids.hrc> +#endif +#include <salgdi.h> +#include <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_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, + USHORT 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, + BOOL bPrinter, int nDrawMode ) +{ + if( hDC ) + { + HGLOBAL hDrawDIB; + HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB(); + WinSalBitmap* pTmpSalBmp = NULL; + BOOL bPrintDDB = ( bPrinter && hDrawDDB ); + + if( bPrintDDB ) + { + pTmpSalBmp = new WinSalBitmap; + pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() ); + hDrawDIB = pTmpSalBmp->ImplGethDIB(); + } + else + hDrawDIB = rSalBitmap.ImplGethDIB(); + + if( hDrawDIB ) + { + PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); + PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; + PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + + rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); + const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); + + StretchDIBits( hDC, + (int)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); + 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 ); + 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( 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 100644 index 000000000000..d82830a9022f --- /dev/null +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -0,0 +1,2920 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * 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 <tools/prewin.h> +#include <windows.h> +#include <tools/postwin.h> +#include <vcl/sysdata.hxx> +#include "tools/svwin.h" + +#include "wincomp.hxx" +#include "saldata.hxx" +#include "salgdi.h" + +#include "vcl/svapp.hxx" +#include "vcl/outfont.hxx" +#include "vcl/font.hxx" +#include "vcl/fontsubset.hxx" +#include "vcl/sallayout.hxx" + +#include "rtl/logfile.hxx" +#include "rtl/tencinfo.h" +#include "rtl/textcvt.h" +#include "rtl/bootstrap.hxx" + + +#include "osl/module.h" +#include "osl/file.hxx" +#include "osl/thread.hxx" +#include "osl/process.h" + +#include "tools/poly.hxx" +#include "tools/debug.hxx" +#include "tools/stream.hxx" + +#include "basegfx/polygon/b2dpolygon.hxx" +#include "basegfx/polygon/b2dpolypolygon.hxx" +#include "basegfx/matrix/b2dhommatrix.hxx" + +#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; + 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; + } +} + +// ======================================================================= + +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 = (USHORT)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; + } + + aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW; + aDFA.meAntiAlias = ANTIALIAS_DONTKNOW; + + // 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; + } + + aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW; + aDFA.meAntiAlias = ANTIALIAS_DONTKNOW; + + // 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, WIN_BYTE eWinCharSet, WIN_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() ); +} + +// ----------------------------------------------------------------------- + +ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const +{ + mpUnicodeMap->AddReference(); + 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 ); +} + +// ======================================================================= + +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 ) +{ + bool bAvailable = false; + + if ( aSalShlData.mbWNT ) + { + // 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; + + EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW, + (LPARAM)(void*)&bAvailable, 0 ); + } + else + { + ByteString aTemp = ImplSalGetWinAnsiString( rName ); + + // Test, if Font available + LOGFONTA aLogFont; + memset( &aLogFont, 0, sizeof( aLogFont ) ); + aLogFont.lfCharSet = DEFAULT_CHARSET; + + UINT nNameLen = aTemp.Len(); + if ( nNameLen > sizeof( aLogFont.lfFaceName )-1 ) + nNameLen = sizeof( aLogFont.lfFaceName )-1; + memcpy( aLogFont.lfFaceName, aTemp.GetBuffer(), nNameLen ); + aLogFont.lfFaceName[nNameLen] = 0; + + EnumFontFamiliesExA( hDC, &aLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA, + (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( 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 ); + + // limit font requests to MAXFONTHEIGHT + // TODO: share MAXFONTHEIGHT font instance + if( -aLogFont.lfHeight <= MAXFONTHEIGHT ) + o_rFontScale = 1.0; + else + { + o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT; + aLogFont.lfHeight = -MAXFONTHEIGHT; + aLogFont.lfWidth = static_cast<LONG>( aLogFont.lfWidth / 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; + } + } + else + { + if( !mpLogFont ) + // mpLogFont is needed for getting the kerning pairs + // TODO: get them from somewhere else + mpLogFont = new LOGFONTA; + LOGFONTA& aLogFont = *mpLogFont; + 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 + && (stricmp( aLogFont.lfFaceName, "Courier" ) == 0) ) + strncpy( aLogFont.lfFaceName, "Courier New", 11 ); + + // limit font requests to MAXFONTHEIGHT to work around driver problems + // TODO: share MAXFONTHEIGHT font instance + if( -aLogFont.lfHeight <= MAXFONTHEIGHT ) + o_rFontScale = 1.0; + else + { + o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT; + aLogFont.lfHeight = -MAXFONTHEIGHT; + aLogFont.lfWidth = static_cast<LONG>( aLogFont.lfWidth / o_rFontScale ); + } + + hNewFont = ::CreateFontIndirectA( &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 ); + + TEXTMETRICA aTextMetricA; + // when the font doesn't work try a replacement + if ( !::GetTextMetricsA( mhDC, &aTextMetricA ) ) + { + // the selected font doesn't work => try a replacement + // TODO: use its font fallback instead + LOGFONTA aTempLogFont = aLogFont; + strncpy( aTempLogFont.lfFaceName, "Courier New", 11 ); + aTempLogFont.lfPitchAndFamily = FIXED_PITCH; + HFONT hNewFont2 = CreateFontIndirectA( &aTempLogFont ); + ::SelectFont( mhDC, hNewFont2 ); + ::DeleteFont( hNewFont ); + hNewFont = hNewFont2; + } + } + + if( hdcScreen ) + ::ReleaseDC( NULL, hdcScreen ); + + return hNewFont; +} + +USHORT 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 ) +{ + if ( aSalShlData.mbWNT ) + { + wchar_t aFaceName[LF_FACESIZE+60]; + if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) ) + pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName); + } + else + { + char aFaceName[LF_FACESIZE+60]; + if( ::GetTextFaceA( mhDC, sizeof(aFaceName), aFaceName ) ) + pMetric->maName = ImplSalGetUniString( aFaceName ); + } + + TEXTMETRICA aWinMetric; + if( !GetTextMetricsA( mhDC, &aWinMetric ) ) + 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[0] && mpWinFontData[0]->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; + + // #109280# HACK korean only: increase descent for wavelines and impr + if( !aSalShlData.mbWNT ) + if( mpWinFontData[0]->SupportsKorean() ) + pMetric->mnDescent += pMetric->mnExtLeading; + } + + 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 ) +{ + ULONG nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL ); + if ( !nPairs ) + return; + + CHARSETINFO aInfo; + if ( !TranslateCharsetInfo( (DWORD*)(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; + ULONG nOldPairs = pData->mnFontKernPairCount; + KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount; + nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair ); + for ( ULONG i = 0; i < nPairs; i++ ) + { + unsigned char aBuf[2]; + wchar_t nChar; + int nLen; + 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 ( 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++; + } +} + +// ----------------------------------------------------------------------- + +ULONG WinSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs ) +{ + DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ), + "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" ); + + if ( mbFontKernInit ) + { + if( mpFontKernPairs ) + { + delete[] mpFontKernPairs; + mpFontKernPairs = NULL; + } + mnFontKernPairCount = 0; + + if ( aSalShlData.mbWNT ) + { + 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 + } + } + else + { + if ( !mnFontCharSetCount ) + ImplGetAllFontCharSets( this ); + + if ( mnFontCharSetCount <= 1 ) + ImplAddKerningPairs( this ); + else + { + // Query All Kerning Pairs from all possible CharSets + for ( BYTE i = 0; i < mnFontCharSetCount; i++ ) + { + mpLogFont->lfCharSet = mpFontCharSets[i]; + HFONT hNewFont = CreateFontIndirectA( mpLogFont ); + HFONT hOldFont = SelectFont( mhDC, hNewFont ); + ImplAddKerningPairs( this ); + SelectFont( mhDC, hOldFont ); + DeleteFont( hNewFont ); + } + } + } + + 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; +} + +// ----------------------------------------------------------------------- + +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 + { + if( aSalShlData.mbWNT ) + ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) ); + else + { + // poor man's string conversion because converter is gone + int nLen = p->maFontFilePath.getLength(); + char* pNameA = new char[ nLen + 1 ]; + for( int i = 0; i < nLen; ++i ) + pNameA[i] = (char)(p->maFontFilePath.getStr())[i]; + pNameA[ nLen ] = 0; + ::RemoveFontResourceA( pNameA ); + delete[] pNameA; + } + } + + 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; + rDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW; + rDFA.meAntiAlias = ANTIALIAS_DONTKNOW; + + // 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; + if ( !aSalShlData.mbWNT ) + { + // for W98 guess charset preference from active codepage + CHARSETINFO aCharSetInfo; + DWORD nCP = GetACP(); + if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) ) + nPreferedCharSet = aCharSetInfo.ciCharset; + } + + // 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; + aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW; + aDFA.meAntiAlias = ANTIALIAS_DONTKNOW; + + /* + // 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<WIN_BYTE>(nPreferedCharSet), + sal::static_int_cast<WIN_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; + + if ( aSalShlData.mbWNT ) + { + LOGFONTW aLogFont; + memset( &aLogFont, 0, sizeof( aLogFont ) ); + aLogFont.lfCharSet = DEFAULT_CHARSET; + aInfo.mpLogFontW = &aLogFont; + EnumFontFamiliesExW( mhDC, &aLogFont, + (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 ); + } + else + { + LOGFONTA aLogFont; + memset( &aLogFont, 0, sizeof( aLogFont ) ); + aLogFont.lfCharSet = DEFAULT_CHARSET; + aInfo.mpLogFontA = &aLogFont; + EnumFontFamiliesExA( mhDC, &aLogFont, + (FONTENUMPROCA)SalEnumFontsProcExA, (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; + } +} + +// ---------------------------------------------------------------------------- + +void WinSalGraphics::GetDevFontSubstList( OutputDevice* ) +{} + +// ----------------------------------------------------------------------- + +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 = GDI_ERROR; + if ( aSalShlData.mbWNT ) + nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat ); + else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) ) + nSize = ::GetGlyphOutlineA( 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; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalGraphics::GetGlyphOutline( long nIndex, + ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) +{ + rB2DPolyPoly.clear(); + + BOOL bRet = FALSE; + 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; + DWORD nSize1 = GDI_ERROR; + if ( aSalShlData.mbWNT ) + nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat ); + else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) ) + nSize1 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat ); + + if( !nSize1 ) // blank glyphs are ok + bRet = TRUE; + else if( nSize1 != GDI_ERROR ) + { + BYTE* pData = new BYTE[ nSize1 ]; + DWORD nSize2; + if ( aSalShlData.mbWNT ) + nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, + &aGlyphMetrics, nSize1, pData, &aMat ); + else + nSize2 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, + &aGlyphMetrics, nSize1, pData, &aMat ); + + if( nSize1 == nSize2 ) + { + bRet = TRUE; + + 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() ) + { + ::basegfx::B2DHomMatrix aMatrix; + aMatrix.scale( mfFontScale/256, mfFontScale/256 ); + rB2DPolyPoly.transform( aMatrix ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +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); +} + +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; + pWinFontData->UpdateFromHDC( mhDC ); +/*const*/ ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap(); + +#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() ) + { + 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 = pImplFontCharMap->GetGlyphIndex( nGlyphIdx ); + if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution + {/*####*/} + + nRealGlyphIds[i] = nGlyphIdx; + } + + // 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; + USHORT 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<USHORT>( 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<USHORT>(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); + ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap(); + DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" ); + + 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 ); + } + } + } + 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..5c00c786e22d --- /dev/null +++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx @@ -0,0 +1,205 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salgdi.cxx,v $ + * $Revision: 1.36 $ + * + * 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 <wincomp.hxx> +#include <saldata.hxx> +#include <salgdi.h> +#include <tools/debug.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) +#endif + +#include <GdiPlus.h> +#include <GdiPlusEnums.h> +#include <GdiPlusColor.h> + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include <basegfx/polygon/b2dpolygon.hxx> + +// ----------------------------------------------------------------------- + +void impAddB2DPolygonToGDIPlusGraphicsPath(Gdiplus::GraphicsPath& rPath, const basegfx::B2DPolygon& rPolygon) +{ + const 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) + { + aCurr = aNext; + aFCurr = aFNext; + } + } + } +} + +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 + } + + impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolyPolygon.getB2DPolygon(a)); + 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, const basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin eLineJoin) +{ + const sal_uInt32 nCount(rPolygon.count()); + + if(mbPen && nCount) + { + Gdiplus::Graphics aGraphics(mhDC); + Gdiplus::Color aTestColor(255, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); + Gdiplus::Pen aTestPen(aTestColor, Gdiplus::REAL(rLineWidths.getX())); + Gdiplus::GraphicsPath aPath; + + switch(eLineJoin) + { + default : // basegfx::B2DLINEJOIN_NONE : + { + 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; + } + } + + impAddB2DPolygonToGDIPlusGraphicsPath(aPath, rPolygon); + + if(rPolygon.isClosed()) + { + // #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 100644 index 000000000000..5a5703e10944 --- /dev/null +++ b/vcl/win/source/gdi/salnativewidgets-luna.cxx @@ -0,0 +1,1115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salnativewidgets-luna.cxx,v $ + * $Revision: 1.12 $ + * + * 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 "svsys.h" +#include "salgdi.h" +#include "saldata.hxx" +#include "vcl/svapp.hxx" + +#include "rtl/ustring.h" +#include "osl/module.h" + +#include "uxtheme.h" +#include "tmschema.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(); + 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(); +} + +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 + */ +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"); + break; + case CTRL_PROGRESS: + if( nPart == PART_ENTIRE_CONTROL ) + hTheme = getThemeHandle( mhWnd, L"Progress"); + 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. + */ +BOOL WinSalGraphics::hitTestNativeControl( ControlType, + ControlPart, + const Region&, + const Point&, + SalControlHandle&, + BOOL& ) +{ + return FALSE; +} + +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 ) +{ + 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, TS_TRUE, &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; +} + +// ---- + +BOOL ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc, + ControlType nType, + ControlPart nPart, + ControlState nState, + const ImplControlValue& aValue, + SalControlHandle&, + 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 ) + { + SpinbuttonValue *pValue = (SpinbuttonValue*) aValue.getOptionalVal(); + if( pValue ) + { + BOOL bOk = 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 ) + { + SpinbuttonValue *pValue = (SpinbuttonValue*) aValue.getOptionalVal(); + if( pValue ) + { + BOOL bOk = 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; + 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--; + + TabitemValue *pValue = (TabitemValue*) aValue.getOptionalVal(); + if( pValue ) + { + 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; + 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 ) + { + ToolbarValue *pValue = (ToolbarValue*) aValue.getOptionalVal(); + if( pValue && 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 ) + return FALSE; + + MenubarValue *pValue = (MenubarValue*) aValue.getOptionalVal(); + if( pValue ) + rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well + return ImplDrawTheme( hTheme, hDC, iPart, 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 ); + } + + 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) + * rControlHandle: Carries platform dependent data and is maintained by the WinSalGraphics implementation. + * aCaption: A caption or title string (like button text etc) + */ +BOOL WinSalGraphics::drawNativeControl( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + SalControlHandle& rControlHandle, + const OUString& aCaption ) +{ + 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"); + break; + case CTRL_PROGRESS: + if( nPart == PART_ENTIRE_CONTROL ) + hTheme = getThemeHandle( mhWnd, L"Progress"); + break; + default: + hTheme = NULL; + break; + } + + if( !hTheme ) + return false; + + Rectangle buttonRect = rControlRegion.GetBoundRect(); + 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, + rControlHandle, 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) + * rControlHandle: Carries platform dependent data and is maintained by the WinSalGraphics implementation. + * aCaption: A caption or title string (like button text etc) + */ +BOOL WinSalGraphics::drawNativeControlText( ControlType, + ControlPart, + const Region&, + ControlState, + const ImplControlValue&, + SalControlHandle&, + 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) + * rControlHandle: Carries platform dependent data and is maintained by the WinSalGraphics implementation. + * aCaption: A caption or title string (like button text etc) + */ +BOOL WinSalGraphics::getNativeControlRegion( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + ControlState, + const ImplControlValue&, + SalControlHandle&, + const OUString&, + Region &rNativeBoundingRegion, + Region &rNativeContentRegion ) +{ + 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.GetBoundRect() ) ); + 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.GetBoundRect() ) ); + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !rNativeContentRegion.IsEmpty() ) + 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..ecf91aea7c1b --- /dev/null +++ b/vcl/win/source/gdi/salprn.cxx @@ -0,0 +1,2363 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salprn.cxx,v $ + * $Revision: 1.36 $ + * + * 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 __MINGW32__ +#include <excpt.h> +#endif + +#ifndef _OSL_MODULE_H +#include <osl/module.h> +#endif +#include <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salgdi.h> +#include <salframe.h> +#include <vcl/salptype.hxx> +#include <salprn.h> +#include <vcl/print.h> +#include <vcl/jobset.h> + +#include <tools/urlobj.hxx> +#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::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 ULONG ImplWinQueueStatusToSal( DWORD nWinStatus ) +{ + 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; + 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, (USHORT)(pTmp-pPortName) ) ); + pPortName = pTmp; + + // get port names + do + { + pPortName++; + pTmp = pPortName; + while ( *pTmp && (*pTmp != ',') ) + pTmp++; + + String aPortName( ImplSalGetUniString( pPortName, (USHORT)(pTmp-pPortName) ) ); + + // create new entry + // look up if printer was already found in first loop + 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 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 = (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 BOOL ImplTestSalJobSetup( WinSalInfoPrinter* pPrinter, + ImplJobSetup* pSetupData, 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 BOOL ImplUpdateSalJobSetup( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, + 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; + 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<USHORT>( + (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 + 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, 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 ) + { + 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( ULONG i = 0; i < nCount; i++ ) + { + if( CHOOSE_DEVMODE(dmDefaultSource) == pBins[ i ] ) + { + pSetupData->mnPaperBin = (USHORT)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 + { + ULONG nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData ); + WORD* pPapers = NULL; + 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( 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; + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplJobSetupToDevMode( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetupData, 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 ) + { + 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; + ULONG nPaperCount = ImplDeviceCaps( pPrinter, DC_PAPERS, NULL, pSetupData ); + WORD* pPapers = NULL; + 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 ( 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 ( 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; + } + } + } +} + +// ----------------------------------------------------------------------- + +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 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; +} + +// ----------------------------------------------------------------------- + +DuplexMode WinSalInfoPrinter::GetDuplexMode( const ImplJobSetup* pSetupData ) +{ + DuplexMode nRet = DUPLEX_UNKNOWN; + if ( pSetupData &&pSetupData->mpDriverData ) + { + if( aSalShlData.mbWPrinter ) + { + DEVMODEW* pDevMode = SAL_DEVMODE_W( pSetupData ); + if ( pDevMode && (pDevMode->dmFields & DM_DUPLEX )) + { + if ( pDevMode->dmDuplex == DMDUP_SIMPLEX ) + nRet = DUPLEX_OFF; + else + nRet = DUPLEX_ON; + } + } + else + { + DEVMODEA* pDevMode = SAL_DEVMODE_A( pSetupData ); + if ( pDevMode && (pDevMode->dmFields & DM_DUPLEX )) + { + if ( pDevMode->dmDuplex == DMDUP_SIMPLEX ) + nRet = DUPLEX_OFF; + else + nRet = DUPLEX_ON; + } + } + } + return nRet; +} + +// ----------------------------------------------------------------------- + +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; +} + +// ----------------------------------------------------------------------- + +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; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalInfoPrinter::SetPrinterData( ImplJobSetup* pSetupData ) +{ + if ( !ImplTestSalJobSetup( this, pSetupData, FALSE ) ) + return FALSE; + return ImplUpdateSalPrnIC( this, pSetupData ); +} + +// ----------------------------------------------------------------------- + +BOOL WinSalInfoPrinter::SetData( ULONG nFlags, ImplJobSetup* pSetupData ) +{ + ImplJobSetupToDevMode( this, pSetupData, nFlags ); + if ( ImplUpdateSalJobSetup( this, pSetupData, TRUE, NULL ) ) + { + ImplDevModeToJobSetup( this, pSetupData, nFlags ); + return ImplUpdateSalPrnIC( this, pSetupData ); + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +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, 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; +} + +// ----------------------------------------------------------------------- + +ULONG WinSalInfoPrinter::GetCapabilities( const ImplJobSetup* pSetupData, USHORT 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; +} + +// ======================================================================= + +WIN_BOOL CALLBACK SalPrintAbortProc( HDC hPrnDC, int /* nError */ ) +{ + SalData* pSalData = GetSalData(); + WinSalPrinter* pPrinter; + BOOL bWhile = TRUE; + int i = 0; + + do + { + // Messages verarbeiten + MSG aMsg; + if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) ) + { + 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, ULONG nCopies, BOOL bCollate ) +{ + LPDEVMODEA pNewDevMode = pDevMode; + if ( pDevMode && (nCopies > 1) ) + { + if ( nCopies > 32765 ) + nCopies = 32765; + ULONG nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra; + pNewDevMode = (LPDEVMODEA)rtl_allocateMemory( nDevSize ); + memcpy( pNewDevMode, pDevMode, nDevSize ); + pDevMode = pNewDevMode; + pDevMode->dmFields |= DM_COPIES; + pDevMode->dmCopies = (short)(USHORT)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, ULONG nCopies, BOOL bCollate ) +{ + LPDEVMODEW pNewDevMode = pDevMode; + if ( pDevMode && (nCopies > 1) ) + { + if ( nCopies > 32765 ) + nCopies = 32765; + ULONG nDevSize = pDevMode->dmSize+pDevMode->dmDriverExtra; + pNewDevMode = (LPDEVMODEW)rtl_allocateMemory( nDevSize ); + memcpy( pNewDevMode, pDevMode, nDevSize ); + pDevMode = pNewDevMode; + pDevMode->dmFields |= DM_COPIES; + pDevMode->dmCopies = (short)(USHORT)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; +} + +BOOL WinSalPrinter::StartJob( const XubString* pFileName, + const XubString& rJobName, + const XubString&, + ULONG nCopies, BOOL bCollate, + 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 + BOOL bWhile = TRUE; + int i = 0; + do + { + // Messages verarbeiten + MSG aMsg; + if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) ) + { + 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()) ) + { + + Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() ); + if( xFactory.is() ) + { + 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" ); + + Reference< XInitialization > xInit( xFilePicker, UNO_QUERY ); + 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; +} + +// ----------------------------------------------------------------------- + +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(); + 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; +} + +// ----------------------------------------------------------------------- + +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, 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; +} + +// ----------------------------------------------------------------------- + +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; + } +} + +// ----------------------------------------------------------------------- + +ULONG WinSalPrinter::GetErrorCode() +{ + return mnError; +} diff --git a/vcl/win/source/gdi/salvd.cxx b/vcl/win/source/gdi/salvd.cxx new file mode 100644 index 000000000000..300bfd9cd6a8 --- /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 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salvd.cxx,v $ + * $Revision: 1.14 $ + * + * 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 <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salgdi.h> +#include <salvd.h> +#include <vcl/sysdata.hxx> + +// ======================================================================= + +static HBITMAP ImplCreateVirDevBitmap( HDC hDC, long nDX, long nDY, + USHORT 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, + USHORT nBitCount, + const SystemGraphicsData* pData ) +{ + WinSalGraphics* pGraphics = static_cast<WinSalGraphics*>(pSGraphics); + + HDC hDC = NULL; + HBITMAP hBmp = NULL; + 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; +} + +// ----------------------------------------------------------------------- + +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 100644 index 000000000000..bf56b2a1082b --- /dev/null +++ b/vcl/win/source/gdi/winlayout.cxx @@ -0,0 +1,3203 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * 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 "salgdi.h" +#include "saldata.hxx" +// for GetMirroredChar +#include "sft.hxx" + +#include "vcl/sallayout.hxx" +#include "vcl/svapp.hxx" + +#include "rtl/ustring.hxx" + +#include "osl/module.h" +#include "osl/file.h" + + +#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 <vcl/graphite_layout.hxx> +#include <vcl/graphite_cache.hxx> +#include <vcl/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; + + HFONT hHugeFont = 0; + if( aSalShlData.mbWNT ) + { + LOGFONTW aLogFont; + ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont); + aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight); + aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth); + hHugeFont = ::CreateFontIndirectW( &aLogFont); + } + else + { + LOGFONTA aLogFont; + ::GetObjectA( mhFont, sizeof(LOGFONTA), &aLogFont); + aLogFont.lfHeight = (LONG)(mfFontScale * aLogFont.lfHeight); + aLogFont.lfWidth = (LONG)(mfFontScale * aLogFont.lfWidth); + hHugeFont = ::CreateFontIndirectA( &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#, limit the number of glyphs to avoid paint errors + UINT limitedGlyphCount = Min( 8192, mnGlyphCount ); + if( mnDrawOptions || aSalShlData.mbWNT ) + { + // #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) + unsigned int i,n; + POINT oldPos; + UINT oldTa = ::GetTextAlign( aHDC ); + ::SetTextAlign( aHDC, (oldTa & ~TA_NOUPDATECP) | TA_UPDATECP ); + ::MoveToEx( aHDC, aPos.X(), aPos.Y(), &oldPos ); + for( i=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 ); + } + else + { + // #108267#, On Win9x, we get paint errors when drawing huge strings, even when + // split into pieces (see above), seems to be a problem in the internal text clipping + // so we just cut off the string + if( !mpGlyphOrigAdvs ) + ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), 0, NULL, + mpOutGlyphs, limitedGlyphCount, NULL ); + else + { + // workaround for problem in #106259# + long nXPos = mnBaseAdv; + for( unsigned int i = 0; i < limitedGlyphCount; ++i ) + { + ::ExtTextOutW( aHDC, aPos.X(), aPos.Y(), 0, NULL, + mpOutGlyphs+i, 1, NULL ); + nXPos += mpGlyphAdvances[ i ]; + aPos = GetDrawPosition( Point( nXPos, 0 ) ); + } + } + } + + 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 ); + WIN_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; + } +} + +// ----------------------------------------------------------------------- + +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; + 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; + + // 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 ]; + } + } + } + + // 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 gr::WinFont 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) +{ + 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 100644 index 000000000000..736f4c4dc8e7 --- /dev/null +++ b/vcl/win/source/gdi/wntgdi.cxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: wntgdi.cxx,v $ + * $Revision: 1.5 $ + * + * 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 Binary files differnew file mode 100644 index 000000000000..b9d56fcd14c1 --- /dev/null +++ b/vcl/win/source/src/50.bmp diff --git a/vcl/win/source/src/50.png b/vcl/win/source/src/50.png Binary files differnew file mode 100644 index 000000000000..8517d965f0b9 --- /dev/null +++ b/vcl/win/source/src/50.png diff --git a/vcl/win/source/src/MAKEFILE.MK b/vcl/win/source/src/MAKEFILE.MK new file mode 100644 index 000000000000..975b1a20330e --- /dev/null +++ b/vcl/win/source/src/MAKEFILE.MK @@ -0,0 +1,134 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: MAKEFILE.MK,v $ +# +# $Revision: 1.10 $ +# +# 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. +# +#************************************************************************* + + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=salsrc + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- #105371# +CFLAGS += -DWINVER=0x0400 + +# --- Files -------------------------------------------------------- + +RCDEPN= nullptr.cur \ + help.cur \ + hsize.cur \ + vsize.cur \ + neswsize.cur \ + nwsesize.cur \ + cross.cur \ + move.cur \ + hsplit.cur \ + vsplit.cur \ + hsizebar.cur \ + vsizebar.cur \ + hand.cur \ + refhand.cur \ + pen.cur \ + magnify.cur \ + fill.cur \ + rotate.cur \ + hshear.cur \ + vshear.cur \ + mirror.cur \ + crook.cur \ + crop.cur \ + movept.cur \ + movebw.cur \ + movedata.cur \ + copydata.cur \ + linkdata.cur \ + movedlnk.cur \ + copydlnk.cur \ + movef.cur \ + copyf.cur \ + linkf.cur \ + moveflnk.cur \ + copyflnk.cur \ + movef2.cur \ + copyf2.cur \ + notallow.cur \ + dline.cur \ + drect.cur \ + dpolygon.cur \ + dbezier.cur \ + darc.cur \ + dpie.cur \ + dcirccut.cur \ + dellipse.cur \ + dfree.cur \ + dconnect.cur \ + dtext.cur \ + dcapt.cur \ + chart.cur \ + detectiv.cur \ + pivotcol.cur \ + pivotrow.cur \ + pivotfld.cur \ + pivotdel.cur \ + chain.cur \ + chainnot.cur \ + timemove.cur \ + timesize.cur \ + asn.cur \ + ass.cur \ + asw.cur \ + ase.cur \ + asnw.cur \ + asne.cur \ + assw.cur \ + asse.cur \ + asns.cur \ + aswe.cur \ + asnswe.cur \ + airbrush.cur \ + vtext.cur \ + tblsels.cur \ + tblsele.cur \ + tblselse.cur \ + tblselw.cur \ + tblselsw.cur \ + pntbrsh.cur \ + 50.bmp \ + sd.ico + +RCFILES= salsrc.rc + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/win/source/src/airbrush.cur b/vcl/win/source/src/airbrush.cur Binary files differnew file mode 100644 index 000000000000..f6a684e6fcbd --- /dev/null +++ b/vcl/win/source/src/airbrush.cur diff --git a/vcl/win/source/src/ase.cur b/vcl/win/source/src/ase.cur Binary files differnew file mode 100755 index 000000000000..7634a7d34a7b --- /dev/null +++ b/vcl/win/source/src/ase.cur diff --git a/vcl/win/source/src/asn.cur b/vcl/win/source/src/asn.cur Binary files differnew file mode 100755 index 000000000000..e444e42bf37e --- /dev/null +++ b/vcl/win/source/src/asn.cur diff --git a/vcl/win/source/src/asne.cur b/vcl/win/source/src/asne.cur Binary files differnew file mode 100755 index 000000000000..e92cc65e7eb1 --- /dev/null +++ b/vcl/win/source/src/asne.cur diff --git a/vcl/win/source/src/asns.cur b/vcl/win/source/src/asns.cur Binary files differnew file mode 100755 index 000000000000..04d0b09c353e --- /dev/null +++ b/vcl/win/source/src/asns.cur diff --git a/vcl/win/source/src/asnswe.cur b/vcl/win/source/src/asnswe.cur Binary files differnew file mode 100755 index 000000000000..a0e25b16de1f --- /dev/null +++ b/vcl/win/source/src/asnswe.cur diff --git a/vcl/win/source/src/asnw.cur b/vcl/win/source/src/asnw.cur Binary files differnew file mode 100755 index 000000000000..20322bc97b16 --- /dev/null +++ b/vcl/win/source/src/asnw.cur diff --git a/vcl/win/source/src/ass.cur b/vcl/win/source/src/ass.cur Binary files differnew file mode 100755 index 000000000000..7166636a1a77 --- /dev/null +++ b/vcl/win/source/src/ass.cur diff --git a/vcl/win/source/src/asse.cur b/vcl/win/source/src/asse.cur Binary files differnew file mode 100755 index 000000000000..8cb71234b0a9 --- /dev/null +++ b/vcl/win/source/src/asse.cur diff --git a/vcl/win/source/src/assw.cur b/vcl/win/source/src/assw.cur Binary files differnew file mode 100755 index 000000000000..fddaf3f57cbf --- /dev/null +++ b/vcl/win/source/src/assw.cur diff --git a/vcl/win/source/src/asw.cur b/vcl/win/source/src/asw.cur Binary files differnew file mode 100755 index 000000000000..0ccac50f4596 --- /dev/null +++ b/vcl/win/source/src/asw.cur diff --git a/vcl/win/source/src/aswe.cur b/vcl/win/source/src/aswe.cur Binary files differnew file mode 100755 index 000000000000..c238b7e10aef --- /dev/null +++ b/vcl/win/source/src/aswe.cur diff --git a/vcl/win/source/src/chain.cur b/vcl/win/source/src/chain.cur Binary files differnew file mode 100755 index 000000000000..02abb7ab714f --- /dev/null +++ b/vcl/win/source/src/chain.cur diff --git a/vcl/win/source/src/chainnot.cur b/vcl/win/source/src/chainnot.cur Binary files differnew file mode 100755 index 000000000000..938ece03f329 --- /dev/null +++ b/vcl/win/source/src/chainnot.cur diff --git a/vcl/win/source/src/chart.cur b/vcl/win/source/src/chart.cur Binary files differnew file mode 100644 index 000000000000..25fe85b76039 --- /dev/null +++ b/vcl/win/source/src/chart.cur diff --git a/vcl/win/source/src/copydata.cur b/vcl/win/source/src/copydata.cur Binary files differnew file mode 100644 index 000000000000..d3c4bc93afd5 --- /dev/null +++ b/vcl/win/source/src/copydata.cur diff --git a/vcl/win/source/src/copydlnk.cur b/vcl/win/source/src/copydlnk.cur Binary files differnew file mode 100644 index 000000000000..495fd5e17776 --- /dev/null +++ b/vcl/win/source/src/copydlnk.cur diff --git a/vcl/win/source/src/copyf.cur b/vcl/win/source/src/copyf.cur Binary files differnew file mode 100644 index 000000000000..450c09443a84 --- /dev/null +++ b/vcl/win/source/src/copyf.cur diff --git a/vcl/win/source/src/copyf2.cur b/vcl/win/source/src/copyf2.cur Binary files differnew file mode 100644 index 000000000000..ac8de5da6ba5 --- /dev/null +++ b/vcl/win/source/src/copyf2.cur diff --git a/vcl/win/source/src/copyflnk.cur b/vcl/win/source/src/copyflnk.cur Binary files differnew file mode 100644 index 000000000000..e67f0539fa43 --- /dev/null +++ b/vcl/win/source/src/copyflnk.cur diff --git a/vcl/win/source/src/crook.cur b/vcl/win/source/src/crook.cur Binary files differnew file mode 100644 index 000000000000..c40cf591e261 --- /dev/null +++ b/vcl/win/source/src/crook.cur diff --git a/vcl/win/source/src/crop.cur b/vcl/win/source/src/crop.cur Binary files differnew file mode 100644 index 000000000000..327fb06976c2 --- /dev/null +++ b/vcl/win/source/src/crop.cur diff --git a/vcl/win/source/src/cross.cur b/vcl/win/source/src/cross.cur Binary files differnew file mode 100644 index 000000000000..8fd9762386b1 --- /dev/null +++ b/vcl/win/source/src/cross.cur diff --git a/vcl/win/source/src/darc.cur b/vcl/win/source/src/darc.cur Binary files differnew file mode 100644 index 000000000000..38504fa23c4a --- /dev/null +++ b/vcl/win/source/src/darc.cur diff --git a/vcl/win/source/src/dbezier.cur b/vcl/win/source/src/dbezier.cur Binary files differnew file mode 100644 index 000000000000..f630b837ddf8 --- /dev/null +++ b/vcl/win/source/src/dbezier.cur diff --git a/vcl/win/source/src/dcapt.cur b/vcl/win/source/src/dcapt.cur Binary files differnew file mode 100644 index 000000000000..10dd5ba0d676 --- /dev/null +++ b/vcl/win/source/src/dcapt.cur diff --git a/vcl/win/source/src/dcirccut.cur b/vcl/win/source/src/dcirccut.cur Binary files differnew file mode 100644 index 000000000000..b19d3f8257f4 --- /dev/null +++ b/vcl/win/source/src/dcirccut.cur diff --git a/vcl/win/source/src/dconnect.cur b/vcl/win/source/src/dconnect.cur Binary files differnew file mode 100644 index 000000000000..5318d8f22d8b --- /dev/null +++ b/vcl/win/source/src/dconnect.cur diff --git a/vcl/win/source/src/dellipse.cur b/vcl/win/source/src/dellipse.cur Binary files differnew file mode 100644 index 000000000000..c489a640335e --- /dev/null +++ b/vcl/win/source/src/dellipse.cur diff --git a/vcl/win/source/src/detectiv.cur b/vcl/win/source/src/detectiv.cur Binary files differnew file mode 100644 index 000000000000..30e5685b64b2 --- /dev/null +++ b/vcl/win/source/src/detectiv.cur diff --git a/vcl/win/source/src/dfree.cur b/vcl/win/source/src/dfree.cur Binary files differnew file mode 100644 index 000000000000..3ff56d007648 --- /dev/null +++ b/vcl/win/source/src/dfree.cur diff --git a/vcl/win/source/src/dline.cur b/vcl/win/source/src/dline.cur Binary files differnew file mode 100644 index 000000000000..623c33ac2351 --- /dev/null +++ b/vcl/win/source/src/dline.cur diff --git a/vcl/win/source/src/dpie.cur b/vcl/win/source/src/dpie.cur Binary files differnew file mode 100644 index 000000000000..3b911cd01e43 --- /dev/null +++ b/vcl/win/source/src/dpie.cur diff --git a/vcl/win/source/src/dpolygon.cur b/vcl/win/source/src/dpolygon.cur Binary files differnew file mode 100644 index 000000000000..9467f1e286aa --- /dev/null +++ b/vcl/win/source/src/dpolygon.cur diff --git a/vcl/win/source/src/drect.cur b/vcl/win/source/src/drect.cur Binary files differnew file mode 100644 index 000000000000..60a5242c203c --- /dev/null +++ b/vcl/win/source/src/drect.cur diff --git a/vcl/win/source/src/dtext.cur b/vcl/win/source/src/dtext.cur Binary files differnew file mode 100644 index 000000000000..01e7d31eae7e --- /dev/null +++ b/vcl/win/source/src/dtext.cur diff --git a/vcl/win/source/src/fill.cur b/vcl/win/source/src/fill.cur Binary files differnew file mode 100644 index 000000000000..78f5fad87ad0 --- /dev/null +++ b/vcl/win/source/src/fill.cur diff --git a/vcl/win/source/src/hand.cur b/vcl/win/source/src/hand.cur Binary files differnew file mode 100644 index 000000000000..fc0e53b474e2 --- /dev/null +++ b/vcl/win/source/src/hand.cur diff --git a/vcl/win/source/src/help.cur b/vcl/win/source/src/help.cur Binary files differnew file mode 100644 index 000000000000..e59ee97992b3 --- /dev/null +++ b/vcl/win/source/src/help.cur diff --git a/vcl/win/source/src/hshear.cur b/vcl/win/source/src/hshear.cur Binary files differnew file mode 100644 index 000000000000..5cf2211458c3 --- /dev/null +++ b/vcl/win/source/src/hshear.cur diff --git a/vcl/win/source/src/hsize.cur b/vcl/win/source/src/hsize.cur Binary files differnew file mode 100644 index 000000000000..571dd0ef703c --- /dev/null +++ b/vcl/win/source/src/hsize.cur diff --git a/vcl/win/source/src/hsizebar.cur b/vcl/win/source/src/hsizebar.cur Binary files differnew file mode 100644 index 000000000000..dda3483bb5d4 --- /dev/null +++ b/vcl/win/source/src/hsizebar.cur diff --git a/vcl/win/source/src/hsplit.cur b/vcl/win/source/src/hsplit.cur Binary files differnew file mode 100644 index 000000000000..f2f0be363d3a --- /dev/null +++ b/vcl/win/source/src/hsplit.cur diff --git a/vcl/win/source/src/linkdata.cur b/vcl/win/source/src/linkdata.cur Binary files differnew file mode 100644 index 000000000000..e47c1dea2cec --- /dev/null +++ b/vcl/win/source/src/linkdata.cur diff --git a/vcl/win/source/src/linkf.cur b/vcl/win/source/src/linkf.cur Binary files differnew file mode 100644 index 000000000000..6cc498a02610 --- /dev/null +++ b/vcl/win/source/src/linkf.cur diff --git a/vcl/win/source/src/magnify.cur b/vcl/win/source/src/magnify.cur Binary files differnew file mode 100644 index 000000000000..1e32b92351af --- /dev/null +++ b/vcl/win/source/src/magnify.cur diff --git a/vcl/win/source/src/mirror.cur b/vcl/win/source/src/mirror.cur Binary files differnew file mode 100644 index 000000000000..e05eb836eb5d --- /dev/null +++ b/vcl/win/source/src/mirror.cur diff --git a/vcl/win/source/src/move.cur b/vcl/win/source/src/move.cur Binary files differnew file mode 100644 index 000000000000..a407a1298ad5 --- /dev/null +++ b/vcl/win/source/src/move.cur diff --git a/vcl/win/source/src/movebw.cur b/vcl/win/source/src/movebw.cur Binary files differnew file mode 100644 index 000000000000..d079eb9fe20d --- /dev/null +++ b/vcl/win/source/src/movebw.cur diff --git a/vcl/win/source/src/movedata.cur b/vcl/win/source/src/movedata.cur Binary files differnew file mode 100644 index 000000000000..4d67cbe47149 --- /dev/null +++ b/vcl/win/source/src/movedata.cur diff --git a/vcl/win/source/src/movedlnk.cur b/vcl/win/source/src/movedlnk.cur Binary files differnew file mode 100644 index 000000000000..1bb7b0306406 --- /dev/null +++ b/vcl/win/source/src/movedlnk.cur diff --git a/vcl/win/source/src/movef.cur b/vcl/win/source/src/movef.cur Binary files differnew file mode 100644 index 000000000000..6abee2381dcf --- /dev/null +++ b/vcl/win/source/src/movef.cur diff --git a/vcl/win/source/src/movef2.cur b/vcl/win/source/src/movef2.cur Binary files differnew file mode 100644 index 000000000000..d044981a3ffd --- /dev/null +++ b/vcl/win/source/src/movef2.cur diff --git a/vcl/win/source/src/moveflnk.cur b/vcl/win/source/src/moveflnk.cur Binary files differnew file mode 100644 index 000000000000..630fa1bc3e4e --- /dev/null +++ b/vcl/win/source/src/moveflnk.cur diff --git a/vcl/win/source/src/movept.cur b/vcl/win/source/src/movept.cur Binary files differnew file mode 100644 index 000000000000..81d3af5a05c4 --- /dev/null +++ b/vcl/win/source/src/movept.cur diff --git a/vcl/win/source/src/neswsize.cur b/vcl/win/source/src/neswsize.cur Binary files differnew file mode 100644 index 000000000000..c38501ee15a8 --- /dev/null +++ b/vcl/win/source/src/neswsize.cur diff --git a/vcl/win/source/src/notallow.cur b/vcl/win/source/src/notallow.cur Binary files differnew file mode 100644 index 000000000000..90c1dfbb3a97 --- /dev/null +++ b/vcl/win/source/src/notallow.cur diff --git a/vcl/win/source/src/nullptr.cur b/vcl/win/source/src/nullptr.cur Binary files differnew file mode 100644 index 000000000000..28dbb2a903f2 --- /dev/null +++ b/vcl/win/source/src/nullptr.cur diff --git a/vcl/win/source/src/nwsesize.cur b/vcl/win/source/src/nwsesize.cur Binary files differnew file mode 100644 index 000000000000..570cbbb571cc --- /dev/null +++ b/vcl/win/source/src/nwsesize.cur diff --git a/vcl/win/source/src/pen.cur b/vcl/win/source/src/pen.cur Binary files differnew file mode 100644 index 000000000000..040c5dc703e9 --- /dev/null +++ b/vcl/win/source/src/pen.cur diff --git a/vcl/win/source/src/pivotcol.cur b/vcl/win/source/src/pivotcol.cur Binary files differnew file mode 100644 index 000000000000..061b3ba92644 --- /dev/null +++ b/vcl/win/source/src/pivotcol.cur diff --git a/vcl/win/source/src/pivotdel.cur b/vcl/win/source/src/pivotdel.cur Binary files differnew file mode 100644 index 000000000000..4497dacd9983 --- /dev/null +++ b/vcl/win/source/src/pivotdel.cur diff --git a/vcl/win/source/src/pivotfld.cur b/vcl/win/source/src/pivotfld.cur Binary files differnew file mode 100644 index 000000000000..efbbead8930c --- /dev/null +++ b/vcl/win/source/src/pivotfld.cur diff --git a/vcl/win/source/src/pivotrow.cur b/vcl/win/source/src/pivotrow.cur Binary files differnew file mode 100644 index 000000000000..649444e9e132 --- /dev/null +++ b/vcl/win/source/src/pivotrow.cur diff --git a/vcl/win/source/src/pntbrsh.cur b/vcl/win/source/src/pntbrsh.cur Binary files differnew file mode 100644 index 000000000000..517d114237c1 --- /dev/null +++ b/vcl/win/source/src/pntbrsh.cur diff --git a/vcl/win/source/src/refhand.cur b/vcl/win/source/src/refhand.cur Binary files differnew file mode 100644 index 000000000000..a654974c6f8b --- /dev/null +++ b/vcl/win/source/src/refhand.cur diff --git a/vcl/win/source/src/rotate.cur b/vcl/win/source/src/rotate.cur Binary files differnew file mode 100644 index 000000000000..43c2a54a10ac --- /dev/null +++ b/vcl/win/source/src/rotate.cur diff --git a/vcl/win/source/src/salsrc.rc b/vcl/win/source/src/salsrc.rc new file mode 100644 index 000000000000..be7cb50204a4 --- /dev/null +++ b/vcl/win/source/src/salsrc.rc @@ -0,0 +1,124 @@ +/************************************************************************* +* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salsrc.rc,v $ + * $Revision: 1.6 $ + * + * 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 <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 Binary files differnew file mode 100644 index 000000000000..b2a0a07a67c3 --- /dev/null +++ b/vcl/win/source/src/sd.ico diff --git a/vcl/win/source/src/tblsele.cur b/vcl/win/source/src/tblsele.cur Binary files differnew file mode 100644 index 000000000000..3683e20df112 --- /dev/null +++ b/vcl/win/source/src/tblsele.cur diff --git a/vcl/win/source/src/tblsels.cur b/vcl/win/source/src/tblsels.cur Binary files differnew file mode 100644 index 000000000000..007182d734de --- /dev/null +++ b/vcl/win/source/src/tblsels.cur diff --git a/vcl/win/source/src/tblselse.cur b/vcl/win/source/src/tblselse.cur Binary files differnew file mode 100644 index 000000000000..986f0139501a --- /dev/null +++ b/vcl/win/source/src/tblselse.cur diff --git a/vcl/win/source/src/tblselsw.cur b/vcl/win/source/src/tblselsw.cur Binary files differnew file mode 100644 index 000000000000..adabba1a2adc --- /dev/null +++ b/vcl/win/source/src/tblselsw.cur diff --git a/vcl/win/source/src/tblselw.cur b/vcl/win/source/src/tblselw.cur Binary files differnew file mode 100644 index 000000000000..a95eb85af49a --- /dev/null +++ b/vcl/win/source/src/tblselw.cur diff --git a/vcl/win/source/src/timemove.cur b/vcl/win/source/src/timemove.cur Binary files differnew file mode 100755 index 000000000000..319b6edc5774 --- /dev/null +++ b/vcl/win/source/src/timemove.cur diff --git a/vcl/win/source/src/timesize.cur b/vcl/win/source/src/timesize.cur Binary files differnew file mode 100755 index 000000000000..1ec23de05b71 --- /dev/null +++ b/vcl/win/source/src/timesize.cur diff --git a/vcl/win/source/src/vshear.cur b/vcl/win/source/src/vshear.cur Binary files differnew file mode 100644 index 000000000000..a4bbf7e8eb00 --- /dev/null +++ b/vcl/win/source/src/vshear.cur diff --git a/vcl/win/source/src/vsize.cur b/vcl/win/source/src/vsize.cur Binary files differnew file mode 100644 index 000000000000..76449be89d0a --- /dev/null +++ b/vcl/win/source/src/vsize.cur diff --git a/vcl/win/source/src/vsizebar.cur b/vcl/win/source/src/vsizebar.cur Binary files differnew file mode 100644 index 000000000000..a87811cb474d --- /dev/null +++ b/vcl/win/source/src/vsizebar.cur diff --git a/vcl/win/source/src/vsplit.cur b/vcl/win/source/src/vsplit.cur Binary files differnew file mode 100644 index 000000000000..a4260808fadc --- /dev/null +++ b/vcl/win/source/src/vsplit.cur diff --git a/vcl/win/source/src/vtext.cur b/vcl/win/source/src/vtext.cur Binary files differnew file mode 100644 index 000000000000..776177901e11 --- /dev/null +++ b/vcl/win/source/src/vtext.cur diff --git a/vcl/win/source/window/MAKEFILE.MK b/vcl/win/source/window/MAKEFILE.MK new file mode 100644 index 000000000000..67cb1bf3e080 --- /dev/null +++ b/vcl/win/source/window/MAKEFILE.MK @@ -0,0 +1,69 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: MAKEFILE.MK,v $ +# +# $Revision: 1.14.94.2 $ +# +# 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. +# +#************************************************************************* + + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=salwin +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- #105371# +.IF "$(COM)"=="GCC" +CFLAGS += -D_WIN32_WINNT=0x0501 +.ELSE +CFLAGS += -DWINVER=0x0400 -D_WIN32_WINNT=0x0501 + +.ENDIF + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/salframe.obj \ + $(SLO)$/salmenu.obj \ + $(SLO)$/salobj.obj + +.IF "$(COM)"=="GCC" +EXCEPTIONSFILES= $(SLO)$/salframe.obj +.ENDIF + +.IF "$(ENABLE_GRAPHITE)" == "TRUE" +CFLAGS+=-DENABLE_GRAPHITE +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx new file mode 100644 index 000000000000..53f822a1e409 --- /dev/null +++ b/vcl/win/source/window/salframe.cxx @@ -0,0 +1,6434 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * 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 <string.h> +#include <limits.h> + +#include <stdio.h> + +#ifndef _SVWIN_HXX +#include <tools/svwin.h> +#endif +#ifdef __MINGW32__ +#include <excpt.h> +#endif +#include <rtl/string.h> +#include <rtl/ustring.h> + +#include <osl/module.h> +#include <tools/debug.hxx> + +// Warning in SDK header +#if defined(_MSC_VER) && (_MSC_VER > 1400) +#pragma warning( disable: 4242 4244 ) +#endif +#include <wincomp.hxx> +#ifndef _SV_SALIDS_HRC +#include <salids.hrc> +#endif +#include <vcl/sysdata.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salbmp.h> +#include <salgdi.h> +#include <salsys.h> +#include <salframe.h> +#include <salvd.h> +#include <salmenu.h> +#include <salobj.h> +#include <vcl/impbmp.hxx> +#include <vcl/timer.hxx> +#include <saltimer.h> +#include <vcl/settings.hxx> +#ifndef _SV_KEYCOES_HXX +#include <vcl/keycodes.hxx> +#endif +#include <vcl/window.h> +#include <vcl/window.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/sallayout.hxx> +#include <vcl/svapp.hxx> +#ifndef _VCL_IMPDEL_HXX +#include <impdel.hxx> +#endif +#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::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 BOOL WINAPI SetLayeredWindowAttributes(HWND,COLORREF,BYTE,DWORD); + typedef 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"); + +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 ); + +static void ImplSaveFrameState( WinSalFrame* pFrame ) +{ + // Position, Groesse und Status fuer GetWindowState() merken + if ( !pFrame->mbFullScreen ) + { + 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; + } + 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, ULONG nSalFrameStyle ) +{ + WinSalFrame* pFrame = new WinSalFrame; + HWND hWnd; + DWORD nSysStyle = 0; + DWORD nExSysStyle = 0; + 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 ( 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 + } + else + { + LPCSTR pClassName; + if ( bSubFrame ) + pClassName = SAL_SUBFRAME_CLASSNAMEA; + else + pClassName = SAL_FRAME_CLASSNAMEA; + hWnd = CreateWindowExA( nExSysStyle, pClassName, "", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, pInst->mhInst, (void*)pFrame ); + } + 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, 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; + } + + HWND hWnd = NULL; + if ( aSalShlData.mbWNT ) + { + LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW; + hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, + hWndParent, 0, hInstance, (void*)GetWindowPtr( oldhWnd ) ); + } + else + { + LPCSTR pClassName = SAL_SUBFRAME_CLASSNAMEA; + hWnd = CreateWindowExA( nExSysStyle, pClassName, "", 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 USHORT 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 + { + Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_QUERY_THROW ); + 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()) ) + { + 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, 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; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalFrame::PostEvent( void* pData ) +{ + return (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( USHORT 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, BOOL bVisible, 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( BOOL bVisible, 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( 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, + USHORT nFlags ) +{ + 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 ); + } + + USHORT 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 + 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, 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; + } + + BOOL bNeedGraphics = pThis->mbGraphics; + 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 + BOOL bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0; + 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; + } + } + + // Wenn Fenster nicht minimiert/maximiert ist oder nicht optisch + // umgesetzt werden muss, dann SetWindowPos() benutzen, da + // SetWindowPlacement() die TaskBar mit einrechnet + if ( !IsIconic( mhWnd ) && !IsZoomed( mhWnd ) && + (!bVisible || (aPlacement.showCmd == SW_RESTORE)) ) + { + if( bUpdateHiddenFramePos ) + { + // #96084 set a useful internal window size because + // the window will not be maximized (and the size updated) before show() + SetMaximizedFrameGeometry( mhWnd, this ); + } + 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 +} + +// ----------------------------------------------------------------------- + +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( 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 + 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( 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( 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, USHORT 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( USHORT 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( 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 ); + 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, USHORT 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( USHORT 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 ( 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=='.'); + } + } + } + else // !mbWnt + { + sal_Char aAnsiKeyBuf[ nMaxKeyLen ]; + int nAnsiKeyLen = GetKeyNameTextA( lParam, aAnsiKeyBuf, nMaxKeyLen ); + DBG_ASSERT( nAnsiKeyLen <= nMaxKeyLen, "Invalid key name length!" ); + if( nAnsiKeyLen > nMaxKeyLen ) + nAnsiKeyLen = 0; + else if( nAnsiKeyLen > 0 ) + { + // Capitalize just the first letter of key names + // TODO: check MCBS key names + CharLowerBuffA( aAnsiKeyBuf, nAnsiKeyLen ); + + bool bUpper = true; + for( sal_Char *pA=aAnsiKeyBuf, *pE=pA+nAnsiKeyLen; pA < pE; ++pA ) + { + if( bUpper ) + CharUpperBuffA( pA, 1 ); + bUpper = (*pA=='+') || (*pA=='-') || (*pA==' ') || (*pA=='.'); + } + + // Convert to Unicode and copy the data in the Unicode Buffer + nKeyLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + aAnsiKeyBuf, nAnsiKeyLen, aKeyBuf, nMaxKeyLen ); + } + } + } + + 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( USHORT 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) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" ); + } + + if ( nKeyCode & KEY_MOD2 ) + { + nSysCode = MapVirtualKey( VK_MENU, 0 ); + nSysCode = (nSysCode << 16) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" ); + } + + if ( nKeyCode & KEY_SHIFT ) + { + nSysCode = MapVirtualKey( VK_SHIFT, 0 ); + nSysCode = (nSysCode << 16) | (((ULONG)1) << 25); + ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" ); + } + + USHORT nCode = nKeyCode & 0x0FFF; + 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 = (((ULONG)1) << 24); + pReplace = "Down"; + break; + case KEY_UP: + nSysCode = VK_UP; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Up"; + break; + case KEY_LEFT: + nSysCode = VK_LEFT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Left"; + break; + case KEY_RIGHT: + nSysCode = VK_RIGHT; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Right"; + break; + case KEY_HOME: + nSysCode = VK_HOME; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Home"; + break; + case KEY_END: + nSysCode = VK_END; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "End"; + break; + case KEY_PAGEUP: + nSysCode = VK_PRIOR; + nSysCode2 = (((ULONG)1) << 24); + pReplace = "Page Up"; + break; + case KEY_PAGEDOWN: + nSysCode = VK_NEXT; + nSysCode2 = (((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 = (((ULONG)1) << 24); + pReplace = "Insert"; + break; + case KEY_DELETE: + nSysCode = VK_DELETE; + nSysCode2 = (((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< USHORT >(nKeyBufLen) ); +} + +// ----------------------------------------------------------------------- + +XubString WinSalFrame::GetSymbolKeyName( const XubString&, USHORT 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; +} + +// ----------------------------------------------------------------------- + +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( (ULONG)ImplA2I( aValueBuf ) ); + } + + RegCloseKey( hRegKey ); + } + + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + BOOL bCompBorder = (aStyleSettings.GetOptions() & (STYLE_OPTION_MACSTYLE | STYLE_OPTION_UNIXSTYLE)) == 0; + // TODO: once those options vanish: just set bCompBorder to TRUE + // to have the system colors read + aStyleSettings.SetScrollBarSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); // #99956# do not allow huge scrollbars, most of the UI is not scaled anymore + aStyleSettings.SetSpinSize( Min( GetSystemMetrics( SM_CXVSCROLL ), 20 ) ); + aStyleSettings.SetCursorBlinkTime( GetCaretBlinkTime() ); + if ( bCompBorder ) + { + 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() ); + if ( bCompBorder ) + { + 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 ); + } + } + } + // 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)(((USHORT)aColor1.GetRed() + (USHORT)aColor2.GetRed())/2); + BYTE nGreen = (BYTE)(((USHORT)aColor1.GetGreen() + (USHORT)aColor2.GetGreen())/2); + BYTE nBlue = (BYTE)(((USHORT)aColor1.GetBlue() + (USHORT)aColor2.GetBlue())/2); + aStyleSettings.SetCheckedColor( Color( nRed, nGreen, nBlue ) ); + } + + // 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 ( 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 ); + } + } + else + { + NONCLIENTMETRICSA aNonClientMetrics; + aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); + if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) + { + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMenuFont, aMenuFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfStatusFont, aHelpFont ); + ImplSalUpdateStyleFontA( hDC, aNonClientMetrics.lfMessageFont, aAppFont ); + + LOGFONTA aLogFont; + if ( SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) ) + ImplSalUpdateStyleFontA( 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 ); + + WIN_BOOL bDragFull; + if ( SystemParametersInfo( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) ) + { + 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 = (ULONG)ImplA2I( aValueBuf ); + if ( (nValue > 1000) && (nValue < 10000) ) + { + MiscSettings aMiscSettings = rSettings.GetMiscSettings(); + aMiscSettings.SetTwoDigitYearStart( (USHORT)(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 ); + 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( ULONG nRects ) +{ + if( mpClipRgnData ) + delete [] (BYTE*)mpClipRgnData; + 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 + { + 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; + USHORT nEvent = 0; + 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 USHORT ImplSalGetKeyCode( WPARAM wParam ) +{ + USHORT nKeyCode; + + // convert KeyCode + if ( wParam < KEY_TAB_SIZE ) + nKeyCode = aImplTranslateKeyTab[wParam]; + else + { + SalData* pSalData = GetSalData(); + std::map< UINT, USHORT >::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 ) +{ + USHORT 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 ) +{ + 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 + if ( aSalShlData.mbWNT ) + return; + + if ( !nLang ) + { + pFrame->mnInputLang = 0; + pFrame->mnInputCodePage = GetACP(); + } + else if ( bLanguageChange ) + { + sal_Char aBuf[10]; + if ( GetLocaleInfoA( MAKELCID( nLang, SORT_DEFAULT ), LOCALE_IDEFAULTANSICODEPAGE, + aBuf, sizeof(aBuf) ) > 0 ) + { + pFrame->mnInputCodePage = ImplStrToNum( aBuf ); + if ( !pFrame->mnInputCodePage ) + pFrame->mnInputCodePage = GetACP(); + } + else + pFrame->mnInputCodePage = GetACP(); + } +} + + +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 + if ( aSalShlData.mbWNT ) + return (sal_Unicode)nCharCode; + + sal_Char aCharBuf[2]; + int nCharLen; + WCHAR c; + if ( nCharCode > 0xFF ) + { + aCharBuf[0] = (sal_Char)(nCharCode>>8); + aCharBuf[1] = (sal_Char)nCharCode; + nCharLen = 2; + } + else + { + aCharBuf[0] = (sal_Char)nCharCode; + nCharLen = 1; + } + if ( ::MultiByteToWideChar( pFrame->mnInputCodePage, + MB_PRECOMPOSED, + aCharBuf, nCharLen, &c, 1 ) ) + return (sal_Unicode)c; + else + return (sal_Unicode)nCharCode; +} + +// ----------------------------------------------------------------------- + +LanguageType WinSalFrame::GetInputLanguage() +{ + if( !mnInputLang ) + ImplUpdateInputLang( this ); + + if( !mnInputLang ) + return LANGUAGE_DONTKNOW; + else + return (LanguageType) mnInputLang; +} + +// ----------------------------------------------------------------------- + +BOOL WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, KeyCode& rKeyCode ) +{ + 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 BOOL bIgnoreCharMsg = FALSE; + static WPARAM nDeadChar = 0; + static WPARAM nLastVKChar = 0; + static USHORT nLastChar = 0; + static USHORT nLastModKeyCode = 0; + static bool bWaitForModKeyRelease = false; + USHORT nRepeat = LOWORD( lParam )-1; + USHORT 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<USHORT>(KEYGROUP_NUM + wParam - '0'); + else if ( (wParam >= 'A') && (wParam <= 'Z') ) + aKeyEvt.mnCode = sal::static_int_cast<USHORT>(KEYGROUP_ALPHA + wParam - 'A'); + else if ( (wParam >= 'a') && (wParam <= 'z') ) + aKeyEvt.mnCode = sal::static_int_cast<USHORT>(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 + + USHORT 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; + USHORT nEvent; + MSG aCharMsg; + WIN_BOOL bCharPeek = FALSE; + UINT nCharMsg = WM_CHAR; + 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; + + USHORT nRepeat = LOWORD( lParam )-1; + USHORT 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; + USHORT nEvent; + 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; + + USHORT nRepeat = LOWORD( lParam )-1; + USHORT nModCode = 0; + USHORT cKeyCode = (USHORT)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 ) +{ + 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 ) +{ + // 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 + + POINT pt; + GetCursorPos( &pt ); + RECT aRectMouse; + aRectMouse.left = pt.x; + aRectMouse.top = pt.y; + aRectMouse.right = pt.x+2; + aRectMouse.bottom = pt.y+2; + + RECT aRect; + ImplSalGetWorkArea( hWnd, &aRect, &aRectMouse ); + + // 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 ) +{ + USHORT 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 ( aSalShlData.mbWNT ) + { + if ( ImplSalWICompareAscii( (const wchar_t*)lParam, "devices" ) == 0 ) + nSalEvent = SALEVENT_PRINTERCHANGED; + } + else + { + if ( stricmp( (const char*)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( 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; + } + + 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; + BOOL bStdDC; + 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, 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; + BOOL fChecked = (pDI->itemState & ODS_CHECKED) ? TRUE : FALSE; + BOOL fSelected = (pDI->itemState & ODS_SELECTED) ? TRUE : FALSE; + 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); + // BOOL bWindowMenu = (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; + + 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 ) + { + WIN_BOOL bMaximize = IsZoomed( pFrame->mhWnd ); + WIN_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)) ) + { + USHORT 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 BOOL ImplHandleIMEStartComposition( HWND hWnd ) +{ + 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 BOOL ImplHandleIMECompositionInput( WinSalFrame* pFrame, + HIMC hIMC, LPARAM lParam ) +{ + 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; + + USHORT* 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; + + WIN_BYTE* pAttrBuf = NULL; + LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, 0, 0 ); + if ( nAttrLen > 0 ) + { + pAttrBuf = new WIN_BYTE[nAttrLen]; + ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf, nAttrLen ); + } + + if ( pAttrBuf ) + { + xub_StrLen nTextLen = aEvt.maText.Len(); + pSalAttrAry = new USHORT[nTextLen]; + memset( pSalAttrAry, 0, nTextLen*sizeof( USHORT ) ); + for ( xub_StrLen i = 0; (i < nTextLen) && (i < nAttrLen); i++ ) + { + WIN_BYTE nWinAttr = pAttrBuf[i]; + USHORT 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 BOOL ImplHandleIMEComposition( HWND hWnd, LPARAM lParam ) +{ + 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 BOOL ImplHandleIMEEndComposition( HWND hWnd ) +{ + 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 ); + + ULONG nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR); + 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, (USHORT)wParam ); + rDef = FALSE; + break; + case SAL_MSG_SHOW: + ImplSalShow( hWnd, (BOOL)wParam, (BOOL)lParam ); + rDef = FALSE; + break; + case SAL_MSG_SETINPUTCONTEXT: + ImplSalFrameSetInputContext( hWnd, (const SalInputContext*)(void*)lParam ); + rDef = FALSE; + break; + case SAL_MSG_ENDEXTTEXTINPUT: + ImplSalFrameEndExtTextInput( hWnd, (USHORT)(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; +} + +// ----------------------------------------------------------------------- + +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 + 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; +} + +// ----------------------------------------------------------------------- + +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 ) + { + 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 100644 index 000000000000..d3602aeabf0e --- /dev/null +++ b/vcl/win/source/window/salmenu.cxx @@ -0,0 +1,413 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salmenu.cxx,v $ + * $Revision: 1.14 $ + * + * 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 <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <vcl/salgdi.hxx> +#include <salmenu.h> +#include <vcl/menu.hxx> +#include <vcl/sysdata.hxx> +#include <salframe.h> +#include <vcl/impbmp.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; + +// ======================================================================= + +BOOL SalData::IsKnownMenuHandle( HMENU hMenu ) +{ + if( mhMenuSet.find( hMenu ) == mhMenuSet.end() ) + return FALSE; + else + return TRUE; +} + +// ======================================================================= + +// WinSalInst factory methods + +SalMenu* WinSalInstance::CreateMenu( BOOL bMenuBar ) +{ + 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 ); +} + +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, BOOL bCheck ) +{ + if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) ) + ImplDrawMenuBar( this ); +} + +void WinSalMenu::EnableItem( unsigned nPos, 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 100644 index 000000000000..f0bdfc266b0c --- /dev/null +++ b/vcl/win/source/window/salobj.cxx @@ -0,0 +1,841 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: salobj.cxx,v $ + * $Revision: 1.11 $ + * + * 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> + +#ifndef _SVWIN_HXX +#include <tools/svwin.h> +#endif +#include <wincomp.hxx> +#include <saldata.hxx> +#include <salinst.h> +#include <salframe.h> +#include <salobj.h> +#include <tools/debug.hxx> + +// ======================================================================= + +static 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; +} + +// ----------------------------------------------------------------------- + +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 ); +} + +// ----------------------------------------------------------------------- + +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 + 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; + + USHORT nKeyCode = LOWORD( pMsg->wParam ); + // Nur 0-9 und A-Z + if ( ((nKeyCode >= 48) && (nKeyCode <= 57)) || + ((nKeyCode >= 65) && (nKeyCode <= 90)) || + ((nKeyCode >= 97) && (nKeyCode <= 122)) ) + { + 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(); + USHORT 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 ) + { + if ( aSalShlData.mbWNT ) + { + pSalData->mhSalObjMsgHook = SetWindowsHookExW( WH_CALLWNDPROC, + SalSysMsgProc, + pSalData->mhInst, + pSalData->mnAppThreadId ); + } + else + { + pSalData->mhSalObjMsgHook = SetWindowsHookExA( 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; + + // 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 ); +} + +// ----------------------------------------------------------------------- + +USHORT WinSalObject::GetClipRegionType() +{ + return SAL_OBJECT_CLIP_INCLUDERECTS; +} + +// ----------------------------------------------------------------------- + +void WinSalObject::BeginSetClipRegion( ULONG nRectCount ) +{ + 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 + { + 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 ) +{ + ULONG nStyle = 0; + 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( BOOL bVisible ) +{ + if ( bVisible ) + ShowWindow( mhWnd, SW_SHOWNORMAL ); + else + ShowWindow( mhWnd, SW_HIDE ); +} + +// ----------------------------------------------------------------------- + +void WinSalObject::Enable( 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; +} |