1 /* AbiWord
2  * Copyright (C) 1998 AbiSource, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA.
18  */
19 
20 #define WIN32_LEAN_AND_MEAN
21 #define NOWINABLE
22 #define NOMETAFILE
23 #define NOSERVICE
24 #define NOIME
25 #define NOMCX
26 
27 #include <windows.h>
28 #include <winspool.h>
29 
30 #include "gr_Win32Graphics.h"
31 #include "gr_Win32Image.h"
32 #include "gr_Painter.h"
33 
34 #include <xap_Win32App.h>
35 #include <xap_Win32Res_Cursors.rc2>
36 
37 #include "xap_Prefs.h"
38 #include "xap_Frame.h"
39 #include "xap_Dialog_Id.h"
40 #include "xap_Win32Dlg_Print.h"
41 #include "xap_EncodingManager.h"
42 
43 #include "ut_debugmsg.h"
44 #include "ut_assert.h"
45 #include "ut_string.h"
46 #include "ut_std_string.h"
47 #include "ut_Win32OS.h"
48 #include "ut_Win32LocaleString.h"
49 
50 #ifdef __MINGW32__
51 #include <w32api.h>
52 #endif
53 
54 UT_uint32 GR_Win32Graphics::s_iInstanceCount = 0;
55 HDC GR_Win32Graphics::m_defPrintHDC = NULL;
56 
57 #define LOG_WIN32_EXCPT(msg)                                                  \
58 {                                                                             \
59     UT_String __s;                                                            \
60     UT_String_sprintf(__s, "%s (%d): %s",__FILE__, __LINE__, msg);            \
61 	UT_DEBUGMSG(("%s",__s.c_str()));                                          \
62     if(XAP_App::getApp()->getPrefs())                                         \
63     {                                                                         \
64 	    XAP_App::getApp()->getPrefs()->log("gr_Win32Graphics", __s.c_str());  \
65     }                                                                         \
66 }
67 
68 //#define GR_GRAPHICS_DEBUG	1
69 
70 /*****************************************************************/
71 
72 // A small helper class
73 class ABI_EXPORT private_FontReverter
74 {
75 public:
private_FontReverter(GR_Win32Graphics & gr,GR_Font * pOldFont)76 	private_FontReverter(GR_Win32Graphics& gr, GR_Font* pOldFont)
77 	:	m_gr(gr),
78 		m_pOldFont(pOldFont)
79 	{
80 	}
~private_FontReverter()81 	~private_FontReverter()
82 	{
83 		if (m_pOldFont)
84 			m_gr.setFont(m_pOldFont);
85 		// else, Oh joy, no old font to revert to... :-<
86 	}
87 
88 private:
89 	private_FontReverter(const private_FontReverter&);	// no impl
90 	void operator=(const private_FontReverter&);		// no impl
91 
92 	GR_Win32Graphics&	m_gr;
93 	GR_Font*			m_pOldFont;
94 };
95 
96 /*****************************************************************/
97 
_constructorCommonCode(HDC hdc)98 void GR_Win32Graphics::_constructorCommonCode(HDC hdc)
99 {
100 	UT_ASSERT(hdc);
101 
102 	m_iDCFontAllocNo = 0;
103 	m_iPrintDCFontAllocNo = 0;
104 	m_hdc = hdc;
105 	m_printHDC = NULL;
106 	m_nPrintLogPixelsY = 0;
107 	m_hwnd = 0;
108 	m_iLineWidth = 0;	// default to a hairline
109 	m_bPrint = false;
110 	m_bStartPrint = false;
111 	m_bStartPage = false;
112 	m_pFont = NULL;
113 	m_pFontGUI = NULL;
114 	m_bIsPreview = false;
115 
116 	m_cs = GR_Graphics::GR_COLORSPACE_COLOR;
117 	m_cursor = GR_CURSOR_INVALID;
118 
119 	m_clrXorPen = 0;
120 	m_hXorPen = 0;
121 
122 	setCursor(GR_CURSOR_DEFAULT);
123 
124 	m_remapBuffer = NULL;
125 	m_remapBufferSize = 0;
126 	m_remapIndices = NULL;
127 
128 	m_eJoinStyle = JOIN_MITER;
129 	m_eCapStyle  = CAP_PROJECTING;
130 	m_eLineStyle = LINE_SOLID;
131 
132 	setBrush((HBRUSH) GetStockObject(WHITE_BRUSH));	// Default brush
133 
134 	m_nLogPixelsY = GetDeviceCaps(m_hdc, LOGPIXELSY);
135 	int nLogPixelsX = GetDeviceCaps(m_hdc, LOGPIXELSX);
136 	if(m_nLogPixelsY)
137 	{
138 		m_fXYRatio = (double)nLogPixelsX / (double) m_nLogPixelsY;
139 	}
140 	else
141 	{
142 		UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
143 		m_fXYRatio = 1;
144 	}
145 
146 	m_hDevMode = NULL;
147 
148 
149 	typedef struct
150 	{
151 		HPEN hPen;
152 		int	 nStyle;
153 		int  nWidth;
154 		int	 nColour;
155 
156 	} CACHE_PEN;
157 
158 	m_pArPens = new GR_Win32Graphics::CACHE_PEN [_MAX_CACHE_PENS];
159 	memset (m_pArPens, 0, _MAX_CACHE_PENS*sizeof(CACHE_PEN));
160 	m_nArPenPos = 0;
161 
162 	_DoubleBuffering_SetUpDummyBuffer();
163 }
164 
GR_Win32Graphics(HDC hdc,HWND hwnd)165 GR_Win32Graphics::GR_Win32Graphics(HDC hdc, HWND hwnd)
166 {
167 	_constructorCommonCode(hdc);
168 	m_hwnd = hwnd;
169 
170 	// init the print HDC with one for the default printer
171 
172 	if (m_defPrintHDC == NULL) {
173 		m_defPrintHDC = UT_GetDefaultPrinterDC();
174 	}
175 
176 	m_printHDC = m_defPrintHDC;
177 	s_iInstanceCount++;
178 
179 	if(m_printHDC)
180 	{
181 		m_nPrintLogPixelsY = GetDeviceCaps(getPrintDC(), LOGPIXELSY);
182 		int nLogPixelsX = GetDeviceCaps(getPrintDC(), LOGPIXELSX);
183 		if(m_nPrintLogPixelsY)
184 		{
185 			m_fXYRatioPrint = (double)nLogPixelsX / (double) m_nPrintLogPixelsY;
186 		}
187 		else
188 		{
189 			UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
190 			m_fXYRatioPrint = 1;
191 		}
192 	}
193 }
194 
setPrintDC(HDC dc)195 void GR_Win32Graphics::setPrintDC(HDC dc)
196 {
197 	if(!m_bPrint)
198 	{
199 		// only do this for screen graphics
200 		m_printHDC = dc;
201 
202 		// now make our views to rebuild themselves ...
203 		// (the win32 graphics currently cannot take advantate of the print dc, so we do nothing
204 	}
205 }
206 
207 
GR_Win32Graphics(HDC hdc,const DOCINFOW * pDocInfo,HGLOBAL hDevMode)208 GR_Win32Graphics::GR_Win32Graphics(HDC hdc, const DOCINFOW * pDocInfo, HGLOBAL hDevMode)
209 {
210 	_constructorCommonCode(hdc);
211  	m_bPrint = true;
212 	m_pDocInfo = pDocInfo;
213 	m_hDevMode = hDevMode;
214 	m_bIsPreview = (hDevMode == NULL);
215 }
216 
~GR_Win32Graphics()217 GR_Win32Graphics::~GR_Win32Graphics()
218 {
219 	_destroyFonts ();
220 	UT_VECTOR_SPARSEPURGEALL( UT_Rect*, m_vSaveRect);
221 	s_iInstanceCount--;
222 
223 	/* Release saved bitmaps */
224 	HBITMAP hBit;
225 	for (UT_sint32 i = 0; i < m_vSaveRectBuf.size (); i++)
226 	{
227 		hBit = (HBITMAP)m_vSaveRectBuf.getNthItem (i);
228 		DeleteObject(hBit);
229 	}
230 
231 	if (m_hXorPen)
232 		DeleteObject(m_hXorPen);
233 
234 	delete [] m_remapBuffer;
235 	delete [] m_remapIndices;
236 
237 	/*Release created pens*/
238 	CACHE_PEN * pArPens =  m_pArPens;
239 	for (int n = 0; n<m_nArPenPos; n++, pArPens++)
240 		DeleteObject(pArPens->hPen);
241 
242 	DELETEPV(m_pArPens);
243 
244 	DELETEP(m_pFontGUI);
245 
246 	_DoubleBuffering_ReleaseDummyBuffer();
247 
248 	if(m_printHDC && m_printHDC != m_defPrintHDC)
249 		DeleteDC(m_printHDC);
250 
251 	if (s_iInstanceCount == 0)
252 		DeleteDC(m_defPrintHDC);
253 
254 }
255 
queryProperties(GR_Graphics::Properties gp) const256 bool GR_Win32Graphics::queryProperties(GR_Graphics::Properties gp) const
257 {
258 	switch (gp)
259 	{
260 	case DGP_SCREEN:
261 		return !m_bPrint;
262 	case DGP_PAPER:
263 		return m_bPrint;
264 	case DGP_OPAQUEOVERLAY:
265 		return true;
266 	default:
267 		UT_ASSERT_HARMLESS(0);
268 		return false;
269 	}
270 }
271 
_newFont(LOGFONTW & lf,double fPoints,HDC hdc,HDC printHDC)272 GR_Win32Font * GR_Win32Graphics::_newFont(LOGFONTW & lf, double fPoints, HDC hdc, HDC printHDC)
273 {
274 	return GR_Win32Font::newFont(lf, fPoints, hdc, printHDC);
275 }
276 
getGUIFont(void)277 GR_Font* GR_Win32Graphics::getGUIFont(void)
278 {
279 	if (!m_pFontGUI)
280 	{
281 		// lazily grab this (once)
282 		HFONT f = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
283 		LOGFONTW lf;
284 		/*int iRes =*/ GetObjectW(f, sizeof(LOGFONTW), &lf);
285 		m_pFontGUI = _newFont(lf, 0, m_hdc, m_hdc);
286 		UT_ASSERT(m_pFontGUI);
287 		DeleteObject(f);
288 	}
289 	if(m_pFontGUI)
290 		m_pFontGUI->markGUIFont();
291 
292 	return m_pFontGUI;
293 }
294 
295 extern "C"
296 int CALLBACK
win32Internal_fontEnumProcedure(ENUMLOGFONTW * pLogFont,NEWTEXTMETRICEXW *,int,LPARAM lParam)297 win32Internal_fontEnumProcedure(ENUMLOGFONTW* pLogFont,
298 								NEWTEXTMETRICEXW* /*pTextMetric*/,
299 								int /*Font_type*/,
300 								LPARAM lParam)
301 {
302 	LOGFONTW *lf = (LOGFONTW*)lParam;
303 	lf->lfCharSet = pLogFont->elfLogFont.lfCharSet;
304 	return 0;
305 }
306 
_findFont(const char * pszFontFamily,const char * pszFontStyle,const char *,const char * pszFontWeight,const char *,const char * pszFontSize,const char *)307 GR_Font* GR_Win32Graphics::_findFont(const char* pszFontFamily,
308 									 const char* pszFontStyle,
309 									 const char* /*pszFontVariant*/,
310 									 const char* pszFontWeight,
311 									 const char* /*pszFontStretch*/,
312 									 const char* pszFontSize,
313 									 const char* /*pszLang*/)
314 {
315 	#ifdef GR_GRAPHICS_DEBUG
316 	UT_DEBUGMSG(("GR_Win32Graphics::findFont %s %s %s\n", pszFontFamily, pszFontStyle, pszFontSize));
317 	#endif
318 
319 	LOGFONTW lf;
320 	memset(&lf, 0, sizeof(lf));
321 
322 	HDC hPrintDC = m_printHDC ? m_printHDC : m_hdc;
323 
324 	/*
325 		TODO we need to fill out the LOGFONT object such that
326 		we'll get the closest possible matching font.  For
327 		now, we're hard-coding a hack.
328 	*/
329 
330 	// we need to get the size in logpixels for the current DC, which
331 	// simply means to divide points by 72 and multiply by device Y resolution
332 
333 	// See: http://support.microsoft.com/support/kb/articles/Q74/2/99.asp
334 	double fPointSize = UT_convertToPoints(pszFontSize);
335 	lf.lfHeight = (int)(-fPointSize * (double)GetDeviceCaps(m_hdc, LOGPIXELSY) / 72.0);
336 
337 	// TODO note that we don't support all those other ways of expressing weight.
338 	if (0 == g_ascii_strcasecmp(pszFontWeight, "bold"))
339 		lf.lfWeight = 700;
340 
341 	// TODO -- remove this block entirely, since oblique is no longer a valid style
342 	// We squash oblique into italic
343 	if (0 == g_ascii_strcasecmp(pszFontStyle, "italic") || 0 == g_ascii_strcasecmp(pszFontStyle, "oblique"))
344 		lf.lfItalic = TRUE;
345 
346 	// TODO note that we currently think pszFontFamily is a single name, not a list!
347 	// TODO why don't these generic family names work?!?
348 	if (0 == g_ascii_strcasecmp(pszFontFamily, "serif"))
349 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_ROMAN;
350 	else if (0 == g_ascii_strcasecmp(pszFontFamily, "sans-serif"))
351 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
352 	else if (0 == g_ascii_strcasecmp(pszFontFamily, "cursive"))
353 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SCRIPT;
354 	else if (0 == g_ascii_strcasecmp(pszFontFamily, "fantasy"))
355 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
356 	else if (0 == g_ascii_strcasecmp(pszFontFamily, "monospace"))
357 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_MODERN;
358 	else
359 	{
360 		// NB: lf.lfFaceName is a statically allocated char buffer of len
361 		// LF_FACESIZE. strToNative() will truncate the string at 500 bytes,
362 		// but as LF_FACESIZE is generally 32, this shouldn't matter.
363 		//
364 		// This convertion is needed because the windows API expects fontnames
365 		// in the native encoding and later lf will be passing to a windows
366 		// API funcion (CreateFontIndirect()).
367     	UT_Win32LocaleString str;
368 		str.fromUTF8 (pszFontFamily);
369 		lstrcpynW(lf.lfFaceName,
370 		        str.c_str(),
371 		        LF_FACESIZE);
372 	}
373 
374 	// Get character set value from the font itself
375 	LOGFONTW enumlf;
376 	memset(&enumlf, 0, sizeof(enumlf));
377 
378 	enumlf.lfCharSet = DEFAULT_CHARSET;
379 	wcscpy(enumlf.lfFaceName, lf.lfFaceName);
380 	EnumFontFamiliesExW(m_hdc, &enumlf,
381 		(FONTENUMPROCW)win32Internal_fontEnumProcedure, (LPARAM)&lf, 0);
382 
383 	lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;		// Choose only True Type fonts.
384 	lf.lfQuality = PROOF_QUALITY;
385 
386 	return _newFont(lf, fPointSize, m_hdc, hPrintDC);
387 }
388 
drawGlyph(UT_uint32,UT_sint32,UT_sint32)389 void GR_Win32Graphics::drawGlyph(UT_uint32 /*Char*/, UT_sint32 /*xoff*/, UT_sint32 /*yoff*/)
390 {
391 	UT_ASSERT_HARMLESS(UT_TODO);
392 }
393 
drawChar(UT_UCSChar Char,UT_sint32 xoff,UT_sint32 yoff)394 void GR_Win32Graphics::drawChar(UT_UCSChar Char, UT_sint32 xoff, UT_sint32 yoff)
395 {
396 	#ifdef GR_GRAPHICS_DEBUG
397 	UT_DEBUGMSG(("GR_Win32Graphics::drawChar %c %u %u\n", Char, xoff, yoff));
398 	#endif
399 
400 	xoff = (UT_sint32)((double)_tduX(xoff) * m_fXYRatio);
401 	yoff = _tduY(yoff);
402 
403 #if 0 // this bypassesthe font handling mechanism
404 	HFONT hFont = m_pFont->getDisplayFont(this);
405 	SelectObject(m_hdc, hFont);
406 #else
407 	m_pFont->selectFontIntoDC(this, m_hdc);
408 #endif
409 
410 	SetTextAlign(m_hdc, TA_LEFT | TA_TOP);
411 	SetBkMode(m_hdc, TRANSPARENT);		// TODO: remember and reset?
412 
413 	UT_UCSChar currentChar = Char;
414 	//TODO this is a temporary hack -- need a way to handle true 32-bit chars
415 	UT_UCS2Char aChar = (UT_UCS2Char) currentChar;
416 
417 	if(currentChar == 0x200B || currentChar == 0xFEFF
418 	   /*|| currentChar == UCS_LIGATURE_PLACEHOLDER*/)
419 		return;
420 	// Windows NT and Windows 95 support the Unicode Font file.
421 	// All of the Unicode glyphs can be rendered if the glyph is found in
422 	// the font file. However, Windows 95 does  not support the Unicode
423 	// characters other than the characters for which the particular codepage
424 	// of the font file is defined.
425 	// Reference Microsoft knowledge base:
426 	// Q145754 - PRB ExtTextOutW or TextOutW Unicode Text Output Is Blank
427 	LOGFONTW lf;
428 	UT_DebugOnly<int> iRes = GetObjectW(m_pFont->getFontHandle(), sizeof(LOGFONTW), &lf);
429 	UT_ASSERT(iRes);
430 	if (UT_IsWinNT() == false && lf.lfCharSet == SYMBOL_CHARSET)
431 	{
432 		// Symbol character handling for Win9x
433 		char str[sizeof(UT_UCS2Char)];
434 
435 		int iConverted = WideCharToMultiByte(CP_ACP, 0,
436 			(LPCWSTR) &aChar, 1,
437 			str, sizeof(str), NULL, NULL);
438 		ExtTextOutA(m_hdc, xoff, yoff, 0, NULL, str, iConverted, NULL);
439 	}
440 	else
441 	{
442 		// Unicode font and default character set handling for WinNT and Win9x
443 		ExtTextOutW(m_hdc, xoff, yoff, 0/*ETO_GLYPH_INDEX*/, NULL, (LPCWSTR) &aChar, 1, NULL);
444 	}
445 }
446 
_remapGlyphs(const UT_UCSChar * pChars,int iCharOffset,int & iLength)447 UT_uint16*	GR_Win32Graphics::_remapGlyphs(const UT_UCSChar* pChars, int iCharOffset, int &iLength)
448 {
449 	// TODO -- make this handle 32-bit chars properly
450 	if (iLength > (int)m_remapBufferSize)
451 	{
452 		delete [] m_remapBuffer;
453 
454 		if(XAP_App::getApp()->theOSHasBidiSupport() != XAP_App::BIDI_SUPPORT_NONE)
455 		{
456 			delete [] m_remapIndices;
457 			m_remapIndices = new UT_UCS2Char[iLength];
458 		}
459 
460 		m_remapBuffer = new UT_UCS2Char[iLength];
461 		m_remapBufferSize = iLength;
462 	}
463 
464     // Need to handle zero-width spaces correctly
465 	int i, j;
466 	for (i = 0, j = 0; i < iLength; ++i, ++j)
467 	{
468 		m_remapBuffer[j] = (UT_UCS2Char)pChars[iCharOffset + i];
469 
470 		if(m_remapBuffer[j] == 0x200B || m_remapBuffer[j] == 0xFEFF
471 		   /*|| m_remapBuffer[j] == UCS_LIGATURE_PLACEHOLDER*/)
472 			j--;
473 	}
474 
475 	iLength -= (i - j);
476 
477 	return m_remapBuffer;
478 }
479 
drawChars(const UT_UCSChar * pChars,int iCharOffset,int iLengthOrig,UT_sint32 xoff,UT_sint32 yoff,int * pCharWidths)480 void GR_Win32Graphics::drawChars(const UT_UCSChar* pChars,
481 								 int iCharOffset, int iLengthOrig,
482 								 UT_sint32 xoff, UT_sint32 yoff,
483 								 int * pCharWidths)
484 {
485 	UT_ASSERT(pChars);
486 
487 	if(!iLengthOrig)
488 	{
489 		// I do not want to assert here, as this makes debugging
490 		// virtually impossible
491 		UT_DEBUGMSG(("GR_Win32Graphics::drawChars: asked to draw zero chars !!!\n"));
492 		return;
493 	}
494 
495 	#ifdef GR_GRAPHICS_DEBUG
496 	UT_DEBUGMSG(("GR_Win32Graphics::drawChars %c %u %u\n", pChars, xoff, yoff));
497 	#endif
498 
499 	xoff = (UT_sint32)((double)_tduX(xoff) * m_fXYRatio);
500 	yoff = _tduY(yoff);
501 	int *pCharAdvances = NULL;
502 
503 	// iLength can be modified by _remapGlyphs
504 	int iLength = iLengthOrig;
505 	HFONT hFont = m_pFont->getDisplayFont(this);
506 	SelectObject(m_hdc, hFont);
507 	m_iDCFontAllocNo = m_pFont->getAllocNumber();
508 	SetTextAlign(m_hdc, TA_LEFT | TA_TOP);
509 	SetBkMode(m_hdc, TRANSPARENT);		// TODO: remember and reset?
510 
511 	UT_uint16* currentChars = _remapGlyphs(pChars, iCharOffset, iLength);
512 
513 	// Windows NT and Windows 95 support the Unicode Font file.
514 	// All of the Unicode glyphs can be rendered if the glyph is found in
515 	// the font file. However, Windows 95 does  not support the Unicode
516 	// characters other than the characters for which the particular codepage
517 	// of the font file is defined.
518 	// Reference Microsoft knowledge base:
519 	// Q145754 - PRB ExtTextOutW or TextOutW Unicode Text Output Is Blank
520 	LOGFONTW lf;
521 	int iRes = GetObjectW(hFont, sizeof(LOGFONTW), &lf);
522 	UT_ASSERT(iRes);
523 
524 	if (UT_IsWinNT() == false && lf.lfCharSet == SYMBOL_CHARSET)
525 	{
526 		// Symbol character handling for Win9x
527 		char* str = new char[iLength * sizeof(UT_UCS2Char)];
528 		int iConverted = WideCharToMultiByte(CP_ACP, 0,
529 			(LPCWSTR) currentChars, iLength,
530 			str, iLength * sizeof(UT_UCSChar), NULL, NULL);
531 
532 		ExtTextOutA(m_hdc, xoff, yoff, 0, NULL, str, iConverted, NULL);
533 		delete [] str;
534 	}
535 	else
536 	{
537 		int duCharWidths [256];
538 
539 		if (pCharWidths)
540 		{
541 			if (iLengthOrig > (sizeof(duCharWidths)/sizeof(int)) )
542 				pCharAdvances = new int [iLengthOrig];
543 			else
544 				pCharAdvances = duCharWidths;
545 			UT_ASSERT(pCharAdvances != NULL);
546 
547 			// convert width into display units; since we have removed
548 			// all 0x200B and 0xFEFF characters, we also have to
549 			// remove their entires from the advances
550 			UT_sint32 i,j;
551 			UT_sint32 iwidth = 0;
552 			UT_sint32 iadvance = 0;
553 			UT_sint32 inextAdvance = 0;
554 			for (i = 0, j = 0; i < iLengthOrig; i++)
555 			{
556 				if(! (pChars[iCharOffset+i] == 0x200B || pChars[iCharOffset+i] == 0xFEFF
557 				   /*|| pChars[iCharOffset+i] == UCS_LIGATURE_PLACEHOLDER*/ ) )
558 				{
559 #if 1
560 					// I rather stupidly changed this to the version
561 					// below the #else, but this one produces much
562 					// smaller rounding errors. Tomas, Dec 6, 2003
563 					iwidth += pCharWidths[iCharOffset + i];
564 					inextAdvance = (UT_sint32)((double)_tduX(iwidth) * m_fXYRatio);
565 					pCharAdvances[j] = inextAdvance - iadvance;
566 					iadvance = inextAdvance;
567 #else
568 					pCharAdvances[j] = tdu(pCharWidths[iCharOffset + i]);
569 #endif
570 					j++;
571 				}
572 			}
573 		}
574 		else
575 		  {
576 			pCharAdvances=NULL;
577 		  }
578 
579 		// Unicode font and default character set handling for WinNT and Win9x
580 
581 		// The bidi aspect of the drawing is handled as follows:
582 		//     1. The OS has no bidi support: use simple ExTextOut
583 		//        call, since all the bidi processing has been already
584 		//        done in the layout engine
585 		//
586 		//     2. If the OS has bidi support: we will not use it for
587 		//        drawing in the main window, only let the system to
588 		//        handle processing for the GUI. This requires that we
589 		//        call GetCharacterPlacement function without
590 		//        requesting reordering and then feed the indices to
591 		//        ExTextOut (direct call to ExTextOut automatically reorders)
592 		if(XAP_App::getApp()->theOSHasBidiSupport() != XAP_App::BIDI_SUPPORT_NONE)
593 		{
594 			UT_ASSERT(m_remapIndices);
595 			GCP_RESULTSW gcpResult;
596 			gcpResult.lStructSize = sizeof(GCP_RESULTSW);
597 			gcpResult.lpOutString = NULL;			// Output string
598 			gcpResult.lpOrder = NULL;				// Ordering indices
599 			// we must set here lpDx to NULL so that
600 			// GetCharacterPlacement does not change our values ...
601 			gcpResult.lpDx = NULL;	                // Distances between character cells
602 			gcpResult.lpCaretPos = NULL;			// Caret positions
603 			gcpResult.lpClass = NULL;				// Character classifications
604 // w32api changed lpGlyphs from UINT * to LPWSTR to match MS PSDK in w32api v2.4
605 #if defined(__MINGW32__) && (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION < 4)
606 			gcpResult.lpGlyphs = (UINT *) m_remapIndices;	// Character glyphs
607 #else
608 			gcpResult.lpGlyphs = (LPWSTR) m_remapIndices;	// Character glyphs
609 #endif
610 			gcpResult.nGlyphs = m_remapBufferSize;  // Array size
611 
612 			DWORD placementResult;
613 
614 			if(XAP_App::getApp()->theOSHasBidiSupport() == XAP_App::BIDI_SUPPORT_GUI)
615 				placementResult = GetCharacterPlacementW(m_hdc, (LPCWSTR) currentChars, iLength, 0, &gcpResult, 0);
616 			else
617 				placementResult = GetCharacterPlacementW(m_hdc, (LPCWSTR) currentChars, iLength, 0, &gcpResult, GCP_REORDER);
618 			// now we set the character advances ...
619 			gcpResult.lpDx = pCharAdvances;	    // Distances between character cells
620 
621 			if(placementResult)
622 			{
623 				ExtTextOutW(m_hdc, xoff, yoff, ETO_GLYPH_INDEX, NULL, (LPCWSTR) m_remapIndices, gcpResult.nGlyphs, pCharAdvances);
624 			}
625 			else
626 			{
627 				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
628 				goto simple_exttextout;
629 			}
630 		}
631 		else
632 		{
633             simple_exttextout:
634 			ExtTextOutW(m_hdc, xoff, yoff, 0, NULL, (LPCWSTR) currentChars, iLength, pCharAdvances);
635 		}
636 
637 		if (pCharAdvances && (iLengthOrig > (sizeof(duCharWidths)/sizeof(int))) )
638 			delete[] pCharAdvances;
639 	}
640 }
641 
setFont(const GR_Font * pFont)642 void GR_Win32Graphics::setFont(const GR_Font* pFont)
643 {
644 	UT_ASSERT(pFont);	// TODO should we allow pFont == NULL?
645 
646 	const GR_Win32Font* pWin32Font = static_cast<const GR_Win32Font*>(pFont);
647 
648 // TMN: This currently won't work since there is no way to tell
649 // GR_Win32Graphics to "drop" a font. If a user of this class:
650 // 1. Creates a new font on the heap.
651 // 2. Calls this setFont()
652 // 3. Deletes the font.
653 // 4. Creates a new font on the heap.
654 // 5. Calls this setFont()
655 // it is possible (and it has happened) that the pointers are the same,
656 // but it's two different fonts.
657 //
658 
659 	// this should work though, the allocation number is unique, even
660 	// if the pointers are identical
661 	if (m_pFont == NULL || pFont->getAllocNumber() != m_iFontAllocNo
662 		|| pWin32Font->getPrimaryHDC() != m_hdc)
663 	{
664 		m_pFont = const_cast<GR_Win32Font*>(pWin32Font);
665 		m_iFontAllocNo = pFont->getAllocNumber();
666 		m_pFont->selectFontIntoDC(this, m_hdc);
667 	}
668 }
669 
getFontHeight(const GR_Font * fnt)670 UT_uint32 GR_Win32Graphics::getFontHeight(const GR_Font * fnt)
671 {
672 	private_FontReverter janitor_(*this, m_pFont);
673 
674 	setFont(fnt);
675 
676 	return getFontHeight();
677 }
678 
getFontHeight()679 UT_uint32 GR_Win32Graphics::getFontHeight()
680 {
681 	UT_return_val_if_fail( m_pFont, 0 );
682 
683 	return (UT_uint32)(m_pFont->getHeight(m_hdc, m_printHDC));
684 }
685 
getFontAscent(const GR_Font * fnt)686 UT_uint32 GR_Win32Graphics::getFontAscent(const GR_Font* fnt)
687 {
688 	private_FontReverter janitor_(*this, m_pFont);
689 
690 	setFont(fnt);
691 
692 	return getFontAscent();
693 }
694 
getFontAscent()695 UT_uint32 GR_Win32Graphics::getFontAscent()
696 {
697 	UT_return_val_if_fail( m_pFont, 0 );
698 	return (UT_uint32)(m_pFont->getAscent(m_hdc, m_printHDC));
699 }
700 
getFontDescent(const GR_Font * fnt)701 UT_uint32 GR_Win32Graphics::getFontDescent(const GR_Font* fnt)
702 {
703 	private_FontReverter janitor_(*this, m_pFont);
704 
705 	setFont(fnt);
706 
707 	return getFontDescent();
708 }
709 
getFontDescent()710 UT_uint32 GR_Win32Graphics::getFontDescent()
711 {
712 	UT_return_val_if_fail( m_pFont, 0 );
713 	return (UT_uint32)(m_pFont->getDescent(m_hdc, m_printHDC));
714 }
715 
getCoverage(UT_NumberVector & coverage)716 void GR_Win32Graphics::getCoverage(UT_NumberVector& coverage)
717 {
718 	coverage.clear();
719 	coverage.push_back(' ');
720 	coverage.push_back((255 - ' '));
721 
722 	//UT_ASSERT(UT_TODO);
723 }
724 
measureUnRemappedChar(const UT_UCSChar c,UT_uint32 *)725 UT_sint32 GR_Win32Graphics::measureUnRemappedChar(const UT_UCSChar c, UT_uint32 * /*height*/)
726 {
727 	#ifdef GR_GRAPHICS_DEBUG
728 	UT_DEBUGMSG(("GR_Win32Graphics::measureUnRemappedChar\n"));
729 	#endif
730 
731 	UT_return_val_if_fail(m_pFont,0);
732 	UT_sint32 iWidth = m_pFont->measureUnRemappedChar(c);
733 
734 	if (iWidth==GR_CW_UNKNOWN || iWidth==GR_CW_ABSENT)
735 		return iWidth;
736 
737 	iWidth *= (UT_sint32)getResolution();
738 	iWidth /= (UT_sint32)getDeviceResolution();
739 	iWidth = (UT_sint32)((double)iWidth * m_fXYRatio);
740 	return iWidth;
741 }
742 
getDeviceResolution(void) const743 UT_uint32 GR_Win32Graphics::getDeviceResolution(void) const
744 {
745 	return m_nLogPixelsY; // NOTE: assumes square pixels
746 }
747 
setColor(const UT_RGBColor & clr)748 void GR_Win32Graphics::setColor(const UT_RGBColor& clr)
749 {
750 	m_curColor = clr;
751 	_setColor(RGB(clr.m_red, clr.m_grn, clr.m_blu));
752 }
753 
getColor(UT_RGBColor & clr)754 void GR_Win32Graphics::getColor(UT_RGBColor& clr)
755 {
756 	clr = m_curColor;
757 }
758 
_setColor(DWORD dwColor)759 void GR_Win32Graphics::_setColor(DWORD dwColor)
760 {
761 	m_clrCurrent = dwColor;
762 	SetTextColor(m_hdc, m_clrCurrent);
763 }
764 
765 #ifdef GR_GRAPHICS_DEBUG
766 static nCacheHit = 0;
767 static nCacheFailed = 0;
768 #endif
769 
drawLine(UT_sint32 x1,UT_sint32 y1,UT_sint32 x2,UT_sint32 y2)770 void GR_Win32Graphics::drawLine(UT_sint32 x1, UT_sint32 y1, UT_sint32 x2, UT_sint32 y2)
771 {
772 	#ifdef GR_GRAPHICS_DEBUG
773 	UT_DEBUGMSG(("GR_Win32Graphics::drawLine %u %u %u %u\n", x1,  y1, x2,  y2));
774 	#endif
775 
776 	x1 = (UT_sint32)((double)_tduX(x1) * m_fXYRatio);
777 	x2 = (UT_sint32)((double)_tduX(x2) * m_fXYRatio);
778 	y1 = _tduY(y1);
779 	y2 = _tduY(y2);
780 
781 	int penStyle;
782 	HPEN hPen = NULL;
783 	bool bCached = false;
784 	UT_sint32 iLineWidth = (UT_sint32)((double)_tduR(m_iLineWidth) * m_fXYRatio);
785 
786 	switch(m_eLineStyle)
787 	{
788 		case LINE_DOUBLE_DASH:
789 		case LINE_ON_OFF_DASH:      penStyle = PS_DASH;  break;
790 		case LINE_SOLID:            penStyle = PS_SOLID; break;
791 		case LINE_DOTTED:           penStyle = PS_DOT;   break;
792 
793 		default:
794 			UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
795 			penStyle = PS_SOLID;
796 	}
797 
798 	/*Look for a cached pen*/
799 	CACHE_PEN * pArPens =  m_pArPens;
800 	for (int n = 0; n<m_nArPenPos; n++, pArPens++)
801 	{
802 		if (pArPens->nStyle==penStyle &&
803 			pArPens->nWidth==iLineWidth &&
804 			pArPens->dwColour==m_clrCurrent)
805 			{
806 				hPen = pArPens->hPen;
807 				bCached = true;
808 #ifdef GR_GRAPHICS_DEBUG
809 				nCacheHit++;
810 #endif
811 				break;
812 			}
813 	}
814 
815 	/*If not cached, let's create it*/
816 	if (!hPen)
817 	{
818 		hPen = CreatePen(penStyle, iLineWidth, m_clrCurrent);
819 
820 		if (m_nArPenPos<_MAX_CACHE_PENS)
821 		{
822 			pArPens =  m_pArPens + m_nArPenPos;
823 			pArPens->nStyle=penStyle;
824 			pArPens->nWidth=iLineWidth;
825 			pArPens->dwColour=m_clrCurrent;
826 			pArPens->hPen = hPen;
827 			bCached = true;
828 			m_nArPenPos++;
829 #ifdef GR_GRAPHICS_DEBUG
830 			nCacheFailed++;
831 #endif
832 		}
833 	}
834 
835 	#ifdef GR_GRAPHICS_DEBUG
836 	UT_DEBUGMSG(("GR_Win32Graphics::drawline: cached elements %u cached hits %u  failed %u\n", m_nArPenPos,
837 		 nCacheHit, nCacheFailed));
838 	#endif
839 
840 	HPEN hOldPen = (HPEN) SelectObject(m_hdc, hPen);
841 
842 	MoveToEx(m_hdc, x1, y1, NULL);
843 	LineTo(m_hdc, x2, y2);
844 
845 	(void) SelectObject(m_hdc, hOldPen);
846 
847 	if (!bCached)
848 		DeleteObject(hPen);
849 }
850 
setLineProperties(double iLineWidth,JoinStyle inJoinStyle,CapStyle inCapStyle,LineStyle inLineStyle)851 void GR_Win32Graphics::setLineProperties(double iLineWidth,
852 										 JoinStyle inJoinStyle,
853 										 CapStyle inCapStyle,
854 										 LineStyle inLineStyle)
855 {
856 	m_eJoinStyle = inJoinStyle;
857 	m_eCapStyle  = inCapStyle;
858 	m_eLineStyle = inLineStyle;
859 	m_iLineWidth = static_cast<UT_sint32>(iLineWidth);
860 }
861 
setLineWidth(UT_sint32 iLineWidth)862 void GR_Win32Graphics::setLineWidth(UT_sint32 iLineWidth)
863 {
864 	m_iLineWidth = iLineWidth;
865 }
866 
xorLine(UT_sint32 x1,UT_sint32 y1,UT_sint32 x2,UT_sint32 y2)867 void GR_Win32Graphics::xorLine(UT_sint32 x1, UT_sint32 y1, UT_sint32 x2, UT_sint32 y2)
868 {
869 	#ifdef GR_GRAPHICS_DEBUG
870 	UT_DEBUGMSG(("GR_Win32Graphics::xorLine %u %u %u %u\n", x1,  y1, x2,  y2));
871 	#endif
872 
873 	/*
874 	  Note that we always use a pixel width of 1 for xorLine, since
875 	  this should always be done to the screen.
876 	*/
877 
878 	x1 = (UT_sint32)((double)_tduX(x1) * m_fXYRatio);
879 	x2 = (UT_sint32)((double)_tduX(x2) * m_fXYRatio);
880 	y1 = _tduY(y1);
881 	y2 = _tduY(y2);
882 
883 	if (m_clrCurrent != m_clrXorPen || !m_hXorPen)
884 	{
885 		if (m_hXorPen)
886 			DeleteObject(m_hXorPen);
887 		m_hXorPen = CreatePen(PS_SOLID, (UT_sint32)((double)_tduR(m_iLineWidth) * m_fXYRatio), m_clrCurrent);
888 		m_clrXorPen = m_clrCurrent;
889 	}
890 
891 	int iROP = SetROP2(m_hdc, R2_XORPEN);
892 	HPEN hOldPen = (HPEN)SelectObject(m_hdc, m_hXorPen);
893 
894 	MoveToEx(m_hdc, x1, y1, NULL);
895 	LineTo(m_hdc, x2, y2);
896 
897 	SelectObject(m_hdc, hOldPen);
898 	SetROP2(m_hdc, iROP);
899 }
900 
polyLine(UT_Point * pts,UT_uint32 nPoints)901 void GR_Win32Graphics::polyLine(UT_Point * pts, UT_uint32 nPoints)
902 {
903 	#ifdef GR_GRAPHICS_DEBUG
904 	UT_DEBUGMSG(("GR_Win32Graphics::polyLine %u\n", nPoints));
905 	#endif
906 
907 	HPEN hPen = CreatePen(PS_SOLID, (UT_sint32)((double)_tduR(m_iLineWidth) * m_fXYRatio), m_clrCurrent);
908 	HPEN hOldPen = (HPEN) SelectObject(m_hdc, hPen);
909 
910 	POINT * points = (POINT *)UT_calloc(nPoints, sizeof(POINT));
911 	UT_return_if_fail(points);
912 
913 	for (UT_uint32 i = 0; i < nPoints; i++)
914 	{
915 		points[i].x = (UT_sint32)((double)_tduX(pts[i].x) * m_fXYRatio);
916 		points[i].y = _tduY(pts[i].y);
917 	}
918 
919 	Polyline(m_hdc, points, nPoints);
920 
921 	(void) SelectObject(m_hdc, hOldPen);
922 	DeleteObject(hPen);
923 	FREEP(points);
924 }
925 
fillRect(const UT_RGBColor & c,UT_sint32 x,UT_sint32 y,UT_sint32 w,UT_sint32 h)926 void GR_Win32Graphics::fillRect(const UT_RGBColor& c, UT_sint32 x, UT_sint32 y, UT_sint32 w, UT_sint32 h)
927 {
928 
929 	RECT r;
930 	r.left = (UT_sint32)((double)_tduX(x) * m_fXYRatio);
931 	r.top = _tduY(y);
932 	r.right = (UT_sint32)(_tduX(x+w) * m_fXYRatio);
933 	r.bottom = _tduY(y+h);
934 
935 	COLORREF clr = RGB(c.m_red, c.m_grn, c.m_blu);
936 
937 	#ifdef GR_GRAPHICS_DEBUG
938 	w=(UT_sint32)((double)_tduR(w) * m_fXYRatio);
939 	h=_tduR(h);
940 	UT_DEBUGMSG(("GR_Win32Graphics::fillRect %x %u %u %u %u\n",  clr, r.left, r.top, w, h));
941 	#endif
942 
943 	// This might look wierd (and I think it is), but it's MUCH faster.
944 	// CreateSolidBrush is dog slow.
945 	HDC hdc = m_hdc;
946 	const COLORREF cr = ::SetBkColor(hdc,  clr);
947 	::ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, NULL, 0, NULL);
948 	::SetBkColor(hdc, cr);
949 }
950 
startPrint(void)951 bool GR_Win32Graphics::startPrint(void)
952 {
953 	UT_ASSERT(m_bPrint);
954 	UT_ASSERT(!m_bStartPrint);
955 
956 	if (!m_bIsPreview)
957 	  {
958 	    m_bStartPrint = ( StartDocW(m_hdc,m_pDocInfo) > 0 );
959 	  }
960 	else
961 	  {
962 	    m_bStartPrint = true;
963 	  }
964 
965 	return m_bStartPrint;
966 }
967 
startPage(const char *,UT_uint32,bool bPortrait,UT_uint32 iWidth,UT_uint32 iHeight)968 bool GR_Win32Graphics::startPage(const char * /*szPageLabel*/, UT_uint32 /*pageNumber*/,
969 									bool bPortrait, UT_uint32 iWidth, UT_uint32 iHeight)
970 {
971 	// need these in 10th of milimiters
972 	iWidth = (int)((double)iWidth * m_fXYRatio * 254.0 / (double)getResolution() + 0.5);
973 	iHeight = iHeight * 254 / getResolution();
974 
975 	if (m_bStartPage)
976 	{
977 		EndPage(m_hdc);
978 	}
979 
980 	// Correct for Portrait vs Lanscape mode
981 	if (m_hDevMode)
982 	{
983 		DEVMODEW *pDevMode = (DEVMODEW*) GlobalLock(m_hDevMode);
984 		UT_return_val_if_fail(pDevMode, false); //GlobalLock can return NULL
985 		pDevMode->dmFields = DM_ORIENTATION | DM_PAPERLENGTH | DM_PAPERWIDTH;
986 		pDevMode->dmOrientation = (bPortrait) ? DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE;
987 		pDevMode->dmPaperSize = 0;
988 		pDevMode->dmPaperLength = (bPortrait) ? iHeight : iWidth;
989 		pDevMode->dmPaperWidth = (bPortrait) ? iWidth : iHeight;
990 
991 		GlobalUnlock(m_hDevMode);
992 
993 		// call DocumentProperties() on the DEVMODE to ensure changes propagate down into
994 		// the private part
995 		fixDevMode(m_hDevMode);
996 
997 		pDevMode = (DEVMODEW*) GlobalLock(m_hDevMode);
998 		ResetDCW(m_hdc, pDevMode);
999 		GlobalUnlock(m_hDevMode);
1000 	}
1001 
1002 	const int iRet = StartPage(m_hdc);
1003 
1004 	if (!m_bIsPreview) {
1005 	  m_bStartPage = iRet > 0;
1006 
1007 	  if (m_bStartPage) {
1008 	      // PHYSICALOFFSETX returns offset of printable area from the left edge
1009 	      // of the physical printer paper. The value returned is in device units.
1010 	      // Since the current mapping mode is MM_TEXT, this code _should_ work.
1011 	      const POINT ptNew = {
1012 		-GetDeviceCaps(m_hdc, PHYSICALOFFSETX),
1013 		-GetDeviceCaps(m_hdc, PHYSICALOFFSETY)
1014 	      };
1015 	      SetViewportOrgEx(m_hdc, ptNew.x, ptNew.y, 0);
1016 	    }
1017 	}
1018 	else {
1019 	  m_bStartPage = true;
1020 	}
1021 
1022 	return m_bStartPage;
1023 }
1024 
endPrint(void)1025 bool GR_Win32Graphics::endPrint(void)
1026 {
1027   if (m_bStartPage) {
1028 		EndPage(m_hdc);
1029   }
1030 
1031   if (!m_bIsPreview)
1032     return (EndDoc(m_hdc) > 0);
1033 
1034   return true;
1035 }
1036 
1037 /**
1038  **  The View calls this when it receives a SetX/YScrollOffset
1039  **  call.  Move the contents of the window appropriately.  View
1040  **  will draw after you exit from this call.  View will only
1041  **  draw into the "exposed" area.
1042  **
1043  ** dx & dy are the change in x/y from the current scrolled position
1044  ** negative values indcate left/up movement, positive right/down movement
1045  **/
scroll(UT_sint32 dx,UT_sint32 dy)1046 void GR_Win32Graphics::scroll(UT_sint32 dx, UT_sint32 dy)
1047 {
1048 	UT_sint32 oldDY = tdu(getPrevYOffset());
1049 	UT_sint32 oldDX = (UT_sint32)((double)tdu(getPrevXOffset()) * m_fXYRatio);
1050 	UT_sint32 newY = getPrevYOffset() + dy;
1051 	UT_sint32 newX = getPrevXOffset() + dx;
1052 	UT_sint32 ddx = -(UT_sint32)((double)(tdu(newX) - oldDX) * m_fXYRatio);
1053 	UT_sint32 ddy = -(tdu(newY) - oldDY);
1054 	setPrevYOffset(newY);
1055 	setPrevXOffset(newX);
1056 	if(ddx == 0 && ddy == 0)
1057 	{
1058 		return;
1059 	}
1060 	GR_Painter caretDisablerPainter(this); // not an elegant way to disable all carets, but it works beautifully - MARCM
1061 
1062 	ScrollWindowEx(m_hwnd, ddx, ddy, NULL, NULL, NULL, 0, SW_INVALIDATE);
1063 }
1064 
scroll(UT_sint32 x_dest,UT_sint32 y_dest,UT_sint32 x_src,UT_sint32 y_src,UT_sint32 width,UT_sint32 height)1065 void GR_Win32Graphics::scroll(UT_sint32 x_dest, UT_sint32 y_dest,
1066 							  UT_sint32 x_src, UT_sint32 y_src,
1067 							  UT_sint32 width, UT_sint32 height)
1068 {
1069 	x_dest = (UT_sint32)((double)tdu(x_dest) * m_fXYRatio);
1070 	y_dest = tdu(y_dest);
1071 	x_src = (UT_sint32)((double)tdu(x_src) * m_fXYRatio);
1072 	y_src = tdu(y_src);
1073 	width = (UT_sint32)((double)tdu(width) * m_fXYRatio);
1074 	height = tdu(height);
1075 	RECT r;
1076 	r.left = x_src;
1077 	r.top = y_src;
1078 	r.right = r.left + width;
1079 	r.bottom = r.top + height;
1080 
1081 	GR_Painter caretDisablerPainter(this); // not an elegant way to disable all carets, but it works beautifully - MARCM
1082 
1083 	ScrollWindowEx(m_hwnd, (x_dest - x_src), (y_dest - y_src),
1084 				   &r, NULL, NULL, NULL, SW_ERASE);
1085 }
1086 
clearArea(UT_sint32 x,UT_sint32 y,UT_sint32 width,UT_sint32 height)1087 void GR_Win32Graphics::clearArea(UT_sint32 x, UT_sint32 y, UT_sint32 width, UT_sint32 height)
1088 {
1089 	#ifdef GR_GRAPHICS_DEBUG
1090 	UT_DEBUGMSG(("GR_Win32Graphics::clearArea %u %u %u %u\n",  x, y, width, height));
1091 	#endif
1092 
1093 	x = (UT_sint32)((double)_tduX(x) * m_fXYRatio);
1094 	y = _tduY(y);
1095 	width = (UT_sint32)((double)_tduR(width) * m_fXYRatio);
1096 	height = _tduR(height);
1097 
1098 	RECT r;
1099 	r.left = x;
1100 	r.top = y;
1101 	r.right = r.left + width;
1102 	r.bottom = r.top + height;
1103 
1104 #if 1
1105 	// for the sake of consistency we should be using the same method as the fillRect()
1106 	// does; however, we already have brush created, so FillRect is probably quicker here
1107 	// (someone should do some profiling on this one day)
1108 	FillRect(m_hdc, &r, m_hClearBrush);
1109 #else
1110 	// this is the method used by fillRect(); if we were to use it, it we should
1111 	// cache lb.lbColor from inside setBrush() to avoid calling GetObject() all the time
1112 	LOGBRUSHW lb;
1113 	GetObjectW(m_hClearBrush, sizeof(LOGBRUSHW), &lb);
1114 
1115 	const COLORREFW cr = ::SetBkColor(m_hdc,  lb.lbColor);
1116 	::ExtTextOutW(m_hdc, 0, 0, ETO_OPAQUE, &r, NULL, 0, NULL);
1117 	::SetBkColor(m_hdc, cr);
1118 #endif
1119 }
1120 
invertRect(const UT_Rect * pRect)1121 void GR_Win32Graphics::invertRect(const UT_Rect* pRect)
1122 {
1123 	#ifdef GR_GRAPHICS_DEBUG
1124 	UT_DEBUGMSG(("GR_Win32Graphics::invertRect\n"));
1125 	#endif
1126 
1127 	RECT r;
1128 
1129 	r.left = (UT_sint32)((double)_tduX(pRect->left) * m_fXYRatio);
1130 	r.top = _tduY(pRect->top);
1131 	r.right = (UT_sint32)((double)_tduX(pRect->left + pRect->width) * m_fXYRatio);
1132 	r.bottom = _tduY(pRect->top + pRect->height);
1133 
1134 	InvertRect(m_hdc, &r);
1135 }
1136 
setClipRect(const UT_Rect * pRect)1137 void GR_Win32Graphics::setClipRect(const UT_Rect* pRect)
1138 {
1139 	// This causes a lot of drawing and screen refresh problems.
1140 	// It can be removed from here without problems, but may
1141 	// not work for other things.  For now leave code in place.
1142 	// return;
1143 
1144 	UT_DebugOnly<int> res;
1145 	m_pRect.reset(pRect);
1146 	if (pRect)
1147 	{
1148 		// set the clip rectangle
1149 		HRGN hrgn = CreateRectRgn((UT_sint32)((double)_tduX(pRect->left) * m_fXYRatio),
1150 								  _tduY(pRect->top),
1151 								  (UT_sint32)((double)_tduX(pRect->left + pRect->width) * m_fXYRatio),
1152 								  _tduY(pRect->top + pRect->height));
1153 		UT_ASSERT(hrgn);
1154 
1155 		res = SelectClipRgn(m_hdc, hrgn);
1156 
1157 		DeleteObject(hrgn);
1158 	}
1159 	else		// stop clipping
1160 		res = SelectClipRgn(m_hdc, NULL);
1161 
1162 	UT_ASSERT_HARMLESS(res != ERROR);
1163 }
1164 
createNewImage(const char * pszName,const UT_ByteBuf * pBB,const std::string & mimetype,UT_sint32 iDisplayWidth,UT_sint32 iDisplayHeight,GR_Image::GRType iType)1165 GR_Image* GR_Win32Graphics::createNewImage(const char* pszName, const UT_ByteBuf* pBB, const std::string& mimetype,
1166 					   UT_sint32 iDisplayWidth, UT_sint32 iDisplayHeight,
1167 					   GR_Image::GRType iType)
1168 {
1169 	iDisplayWidth = (UT_sint32)((double)_tduR(iDisplayWidth) * m_fXYRatio);
1170 	iDisplayHeight = _tduR(iDisplayHeight);
1171 
1172 	GR_Image* pImg = NULL;
1173 	if (iType == GR_Image::GRT_Raster)
1174 		pImg = new GR_Win32Image(pszName);
1175 	else
1176 		pImg = new GR_VectorImage(pszName);
1177 
1178 	pImg->convertFromBuffer(pBB, mimetype, iDisplayWidth,iDisplayHeight);
1179 
1180 	return pImg;
1181 }
1182 
drawImage(GR_Image * pImg,UT_sint32 xDest,UT_sint32 yDest)1183 void GR_Win32Graphics::drawImage(GR_Image* pImg, UT_sint32 xDest, UT_sint32 yDest)
1184 {
1185 	UT_return_if_fail(pImg);
1186 
1187 	xDest = (UT_sint32)((double)_tduX(xDest) * m_fXYRatio);
1188 	yDest = _tduY(yDest);
1189 
1190 	if (pImg->getType() != GR_Image::GRT_Raster)
1191 	{
1192 		pImg->render(this, xDest, yDest);
1193 		return;
1194 	}
1195 
1196 	// When Printing yDest must be within Page Height for each
1197 	// Page.
1198 	if (queryProperties(GR_Graphics::DGP_PAPER))
1199 	{
1200 		UT_sint32 nPageHeight = GetDeviceCaps(m_hdc, PHYSICALHEIGHT);
1201 		yDest = ( yDest % nPageHeight );
1202 	}
1203 
1204 	GR_Win32Image* pWin32Img = static_cast<GR_Win32Image*>(pImg);
1205 
1206 	BITMAPINFO* pDIB = pWin32Img->getDIB();
1207 
1208 	if (pDIB == NULL)
1209 		return;
1210 
1211 	UT_uint32 iSizeOfColorData = pDIB->bmiHeader.biClrUsed * sizeof(RGBQUAD);
1212 	UT_Byte* pBits = ((unsigned char*) pDIB) + pDIB->bmiHeader.biSize + iSizeOfColorData;
1213 
1214 	int iRes = 0;
1215 
1216 #if 0
1217 	// AlphaBlend is supported from win98 upwards
1218 	// we need to turn the DIB into DC first
1219 	HDC memDC = CreateCompatibleDC(m_hdc);
1220 
1221 	if(memDC)
1222 	{
1223 		// need to convert the dib pointer to handle here ...
1224 
1225 		// now select into the memory dc and call AlphaBlend
1226 		SelectObject(memDC, hDIB);
1227 		iRes = AlphaBlend(m_hdc,
1228 						  xDest, yDest,
1229 						  pImg->getDisplayWidth(), pImg->getDisplayHeight(),
1230 						  memDC,
1231 						  0, 0,
1232 						  pDIB->bmiHeader.biWidth, pDIB->bmiHeader.biHeight,
1233 						  blendfnct);
1234 	}
1235 
1236 #endif
1237 
1238 	if(!iRes)
1239 	{
1240 		SetStretchBltMode(m_hdc, COLORONCOLOR);
1241 		iRes = StretchDIBits(m_hdc,
1242 							 xDest, yDest,
1243 							 pImg->getDisplayWidth(), pImg->getDisplayHeight(),
1244 							 0, 0,
1245 							 pDIB->bmiHeader.biWidth, pDIB->bmiHeader.biHeight,
1246 							 pBits, pDIB, DIB_RGB_COLORS, SRCCOPY);
1247 	}
1248 
1249 	if (iRes == GDI_ERROR)
1250 	{
1251 		UT_DebugOnly<DWORD> err = GetLastError();
1252 		UT_DEBUGMSG(("StretchDIBits failed with err %d\n", err));
1253 	}
1254 }
1255 
getHwnd(void) const1256 HWND GR_Win32Graphics::getHwnd(void) const
1257 {
1258 	return m_hwnd;
1259 }
1260 
setColorSpace(GR_Graphics::ColorSpace)1261 void GR_Win32Graphics::setColorSpace(GR_Graphics::ColorSpace /*c*/)
1262 {
1263 	// TODO:  maybe?
1264 	UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1265 }
1266 
getColorSpace(void) const1267 GR_Graphics::ColorSpace GR_Win32Graphics::getColorSpace(void) const
1268 {
1269 	return m_cs;
1270 }
1271 
setCursor(GR_Graphics::Cursor c)1272 void GR_Win32Graphics::setCursor(GR_Graphics::Cursor c)
1273 {
1274 	// set the cursor type, but wait for a WM_SETCURSOR
1275 	// to do anything about it.
1276 	m_cursor = c;
1277 }
1278 
getCursor(void) const1279 GR_Graphics::Cursor GR_Win32Graphics::getCursor(void) const
1280 {
1281 	return m_cursor;
1282 }
1283 
handleSetCursorMessage(void)1284 void GR_Win32Graphics::handleSetCursorMessage(void)
1285 {
1286 	// deal with WM_SETCURSOR message.
1287 
1288 	XAP_Win32App * pWin32App = static_cast<XAP_Win32App *>(XAP_App::getApp());
1289 	HINSTANCE hinst = pWin32App->getInstance();
1290 	LPCTSTR cursor_name;                //TODO : CHECK
1291 
1292 	switch (m_cursor)
1293 	{
1294 	case GR_CURSOR_CROSSHAIR:
1295 		cursor_name = IDC_CROSS;
1296 		hinst = NULL;
1297 		break;
1298 
1299 	default:
1300 	{
1301 		// this assert makes debugging virtuall impossible !!!
1302 		static bool bDoneThisAlready = false;
1303 		if(!bDoneThisAlready)
1304 		{
1305 			bDoneThisAlready = true;
1306 			UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
1307 		}
1308 
1309 	}
1310 		/*FALLTHRU*/
1311 	case GR_CURSOR_DEFAULT:
1312 		cursor_name = IDC_ARROW;		// top-left arrow
1313 		hinst = NULL;
1314 		break;
1315 
1316 	case GR_CURSOR_LINK:
1317 	case GR_CURSOR_GRAB:
1318 #ifndef IDC_HAND
1319 		cursor_name = MAKEINTRESOURCE(IDC_ABIHAND);
1320 #else
1321 		if (UT_IsWin95())
1322 			cursor_name = MAKEINTRESOURCE(IDC_ABIHAND);
1323 		else
1324 		{
1325 			cursor_name = IDC_HAND;
1326 			hinst = NULL;
1327 		}
1328 #endif
1329 		break;
1330 
1331 	case GR_CURSOR_EXCHANGE:
1332 		cursor_name = MAKEINTRESOURCE(IDC_EXCHANGE);
1333 		break;
1334 
1335 	case GR_CURSOR_IBEAM:
1336 		cursor_name = IDC_IBEAM;
1337 		hinst = NULL;
1338 		break;
1339 
1340 	case GR_CURSOR_RIGHTARROW:
1341 		cursor_name = MAKEINTRESOURCE(IDC_ABIRIGHTARROW);
1342 		break;
1343 
1344 	case GR_CURSOR_LEFTARROW:
1345 		cursor_name = IDC_ARROW;		// TODO change this
1346 		hinst = NULL;
1347 		break;
1348 
1349 	case GR_CURSOR_DOWNARROW:
1350 		cursor_name = MAKEINTRESOURCE(IDC_ABIDOWNARROW);
1351 		break;
1352 
1353 	case GR_CURSOR_IMAGE:
1354 		cursor_name = IDC_SIZEALL;
1355 		hinst = NULL;
1356 		break;
1357 
1358 	case GR_CURSOR_IMAGESIZE_NW:
1359 	case GR_CURSOR_IMAGESIZE_SE:
1360 		cursor_name = IDC_SIZENWSE;
1361 		hinst = NULL;
1362 		break;
1363 
1364 	case GR_CURSOR_HLINE_DRAG:
1365 	case GR_CURSOR_UPDOWN:
1366 	case GR_CURSOR_IMAGESIZE_N:
1367 	case GR_CURSOR_IMAGESIZE_S:
1368 		cursor_name = IDC_SIZENS;
1369 		hinst = NULL;
1370 		break;
1371 
1372 	case GR_CURSOR_IMAGESIZE_NE:
1373 	case GR_CURSOR_IMAGESIZE_SW:
1374 		cursor_name = IDC_SIZENESW;
1375 		hinst = NULL;
1376 		break;
1377 
1378 	case GR_CURSOR_VLINE_DRAG:
1379 	case GR_CURSOR_LEFTRIGHT:
1380 	case GR_CURSOR_IMAGESIZE_E:
1381 	case GR_CURSOR_IMAGESIZE_W:
1382 		cursor_name = IDC_SIZEWE;
1383 		hinst = NULL;
1384 		break;
1385 
1386 	case GR_CURSOR_WAIT:
1387 		cursor_name = IDC_WAIT;
1388 		hinst = NULL;
1389 		break;
1390 	}
1391 
1392 	HCURSOR hCursor = LoadCursor(hinst,cursor_name); //TODO: Leaking resource
1393 	if (hCursor != NULL)
1394 		SetCursor(hCursor);
1395 }
1396 
setColor3D(GR_Color3D c)1397 void GR_Win32Graphics::setColor3D(GR_Color3D c)
1398 {
1399 	UT_ASSERT(c < COUNT_3D_COLORS);
1400 	_setColor(m_3dColors[c]);
1401 }
1402 
init3dColors(void)1403 void GR_Win32Graphics::init3dColors(void)
1404 {
1405 	m_3dColors[CLR3D_Foreground] = GetSysColor(COLOR_BTNTEXT);
1406 	m_3dColors[CLR3D_Background] = GetSysColor(COLOR_3DFACE);
1407 	m_3dColors[CLR3D_BevelUp]    = GetSysColor(COLOR_3DHIGHLIGHT);
1408 	m_3dColors[CLR3D_BevelDown]  = GetSysColor(COLOR_3DSHADOW);
1409 	m_3dColors[CLR3D_Highlight]  = GetSysColor(COLOR_WINDOW);
1410 }
1411 
fillRect(GR_Color3D c,UT_sint32 x,UT_sint32 y,UT_sint32 w,UT_sint32 h)1412 void GR_Win32Graphics::fillRect(GR_Color3D c, UT_sint32 x, UT_sint32 y, UT_sint32 w, UT_sint32 h)
1413 {
1414 	UT_ASSERT(c < COUNT_3D_COLORS);
1415 
1416 	#ifdef GR_GRAPHICS_DEBUG
1417 	UT_DEBUGMSG(("GR_Win32Graphics::fillRect GR_Color3D  %x %u %u %u %u\n",  c, x, y, w, h));
1418 	#endif
1419 
1420 	RECT r;
1421 	r.left = (UT_sint32)((double)_tduX(x) * m_fXYRatio);
1422 	r.top = _tduY(y);
1423 	r.right = (UT_sint32)((double)_tduX(x+w) * m_fXYRatio);
1424 	r.bottom = _tduY(y+h);
1425 
1426 	// This might look wierd (and I think it is), but it's MUCH faster.
1427 	// CreateSolidBrush is dog slow.
1428 	HDC hdc = m_hdc;
1429 	COLORREF clr = RGB(GetRValue(m_3dColors[c]), GetGValue(m_3dColors[c]), GetBValue(m_3dColors[c]));
1430 
1431 	const COLORREF cr = ::SetBkColor(hdc,  clr);
1432 	::ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &r, NULL, 0, NULL);
1433 	::SetBkColor(hdc, cr);
1434 }
1435 
fillRect(GR_Color3D c,UT_Rect & r)1436 void GR_Win32Graphics::fillRect(GR_Color3D c, UT_Rect &r)
1437 {
1438 	UT_ASSERT(c < COUNT_3D_COLORS);
1439 	fillRect(c,r.left,r.top,r.width,r.height);
1440 }
1441 
1442 //////////////////////////////////////////////////////////////////
1443 // This is a static method in the GR_Font base class implemented
1444 // in platform code.
1445 //////////////////////////////////////////////////////////////////
1446 
s_getGenericFontProperties(const char * szFontName,FontFamilyEnum * pff,FontPitchEnum * pfp,bool * pbTrueType)1447 void GR_Font::s_getGenericFontProperties(const char * szFontName,
1448 										 FontFamilyEnum * pff,
1449 										 FontPitchEnum * pfp,
1450 										 bool * pbTrueType)
1451 {
1452 	// describe in generic terms the named font.
1453 
1454 	// we borrow some code from GR_Win32Graphics::findFont()
1455 
1456 	LOGFONTW lf;
1457 	memset(&lf, 0, sizeof(lf));
1458 
1459 	TEXTMETRICW tm;
1460 	memset(&tm, 0, sizeof(tm));
1461 
1462 	// TODO i'm not sure why we special case these, but the other
1463 	// TODO code did, so i'm going to here.
1464 
1465 	if (g_ascii_strcasecmp(szFontName, "serif") == 0)
1466 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_ROMAN;
1467 	else if (g_ascii_strcasecmp(szFontName, "sans-serif") == 0)
1468 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
1469 	else if (g_ascii_strcasecmp(szFontName, "cursive") == 0)
1470 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SCRIPT;
1471 	else if (g_ascii_strcasecmp(szFontName, "fantasy") == 0)
1472 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DECORATIVE;
1473 	else if (g_ascii_strcasecmp(szFontName, "monospace") == 0)
1474 		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_MODERN;
1475 	else
1476 	{
1477 		UT_Win32LocaleString str;
1478 		str.fromUTF8 (szFontName);
1479 			lstrcpynW(lf.lfFaceName,
1480 				    str.c_str(),
1481 			        LF_FACESIZE);
1482 	}
1483 
1484 	// let the system create the font with the given name or
1485 	// properties and then query it and see what was actually
1486 	// created.  hopefully, this will let us more accurately
1487 	// reflect what is being seen on screen.
1488 
1489 	HFONT hFont = CreateFontIndirectW(&lf);
1490 	HDC hdc = CreateDCW(L"DISPLAY",NULL,NULL,NULL);
1491 	HFONT hFontOld = (HFONT) SelectObject(hdc,hFont);
1492 	GetTextMetricsW(hdc,&tm);
1493 	SelectObject(hdc,hFontOld);
1494 	DeleteObject(hFont);
1495 	DeleteDC(hdc);
1496 
1497 	BYTE xx = tm.tmPitchAndFamily;
1498 
1499 	switch (xx & 0xf0)
1500 	{
1501 	default:
1502 	case FF_DONTCARE:	*pff = FF_Unknown;		break;
1503 	case FF_ROMAN:		*pff = FF_Roman;		break;
1504 	case FF_SWISS:		*pff = FF_Swiss;		break;
1505 	case FF_MODERN:		*pff = FF_Modern;		break;
1506 	case FF_SCRIPT:		*pff = FF_Script;		break;
1507 	case FF_DECORATIVE:	*pff = FF_Decorative;	break;
1508 	}
1509 
1510 	if ((xx & TMPF_FIXED_PITCH) == TMPF_FIXED_PITCH)
1511 		*pfp = FP_Variable;				// yes these look backwards
1512 	else								// but that is how windows
1513 		*pfp = FP_Fixed;				// defines the bits...
1514 
1515 	*pbTrueType = ((xx & TMPF_TRUETYPE) == TMPF_TRUETYPE);
1516 
1517 	return;
1518 }
1519 
1520 /*!
1521     hdc - the primary hdc on which we are expected to draw
1522     printHDC - the hdc for which to retrive metrics
1523 */
GR_Win32Font(LOGFONTW & lf,double fPoints,HDC hdc,HDC printHDC)1524 GR_Win32Font::GR_Win32Font(LOGFONTW & lf, double fPoints, HDC hdc, HDC printHDC)
1525 :	m_hdc(hdc),
1526 	m_xhdc(0), // once all the processing is done, this is changed to printHDC
1527 	m_yhdc(0), // once all the processing is done, this is changed to printHDC
1528 	m_defaultCharWidth(0),
1529 	m_layoutFont (0),
1530 	m_tm(TEXTMETRICW()),
1531 	m_bGUIFont(false),
1532 	m_fPointSize(fPoints)
1533 {
1534 	m_iHeight = abs(lf.lfHeight);
1535 
1536 	m_layoutFont = CreateFontIndirectW(&lf); // this is what we see to start with
1537 
1538 	if(!m_layoutFont)
1539 	{
1540 		LOG_WIN32_EXCPT("CreateFontIndirectFailed");
1541 		return;
1542 	}
1543 
1544 	insertFontInCache (m_iHeight, m_layoutFont);
1545 
1546 	HFONT printFont = m_layoutFont;
1547 
1548 	if(hdc != printHDC)
1549 	{
1550 		int nPrintLogPixelsY = GetDeviceCaps(printHDC, LOGPIXELSY);
1551 
1552 		// use the point size rather than the screen pixel size to minimise rounding error
1553 		// (lfHeight already carries a rounding error from conversion pts -> screen pixels)
1554 		// lf.lfHeight = MulDiv(lf.lfHeight, nPrintLogPixelsY, nLogPixelsY);
1555 		lf.lfHeight =  (int)(-fPoints * (double)nPrintLogPixelsY / 72.00 + 0.5);
1556 		printFont = CreateFontIndirectW(&lf);
1557 
1558 		if(!printFont)
1559 		{
1560 			LOG_WIN32_EXCPT("CreateFontIndirectFailed");
1561 			return;
1562 		}
1563 
1564 		insertFontInCache(abs(lf.lfHeight), printFont);
1565 
1566 	}
1567 
1568 	//
1569 	// TMN: We need to initialize 'this' to _something_, why we use the
1570 	// screen DC. Note that this is a *bad hack* forced by bad design. :-(
1571 	//
1572 	if (!hdc || !printHDC)
1573 	{
1574 		// NOW what? We can't throw an exeption, and this object isn't
1575 		// legal yet...
1576 		LOG_WIN32_EXCPT("No DC")
1577 		m_layoutFont = NULL;
1578 		return;
1579 	}
1580 	else
1581 	{
1582 		// now we need to retrieve the y-axis metrics
1583 		HFONT hOldFont = (HFONT)SelectObject(printHDC, printFont);
1584 		if (hOldFont == (HFONT)GDI_ERROR)
1585 		{
1586 			LOG_WIN32_EXCPT("Could not select font into DC.")
1587 			m_layoutFont = NULL;
1588 			return;
1589 		}
1590 		else
1591 		{
1592 			// Setting the m_hashKey
1593 			wchar_t lpFaceName[1000];
1594 
1595 			GetTextFaceW(printHDC, 1000, lpFaceName );
1596 
1597 			_updateFontYMetrics(hdc, printHDC);
1598 
1599 			m_hashKey = UT_std_string_sprintf("%s-%ld-%ld-%d-%d-%d-%d-%d",
1600 							  lpFaceName,
1601 							  m_tm.tmHeight, m_tm.tmWeight, m_tm.tmItalic, m_tm.tmUnderlined,
1602 							  m_tm.tmStruckOut,
1603 							  GetDeviceCaps(hdc, LOGPIXELSX),
1604 							  GetDeviceCaps(hdc, LOGPIXELSY));
1605 
1606 			// now we measure the default character
1607 			//
1608 			// when we are called, the char widths might not exist yet; we
1609 			// will force initialisation by a bogus call to
1610 			// getCharWidthFromCache(); by measuring the space, we will
1611 			// preload the entire Latin1 page
1612 			getCharWidthFromCache(' ');
1613 
1614 			UINT d = m_tm.tmDefaultChar;
1615 
1616 			UT_return_if_fail(_getCharWidths());
1617 			_getCharWidths()->setCharWidthsOfRange(printHDC, d, d);
1618 			m_defaultCharWidth = getCharWidthFromCache(d);
1619 
1620 			// this is not good SelectObject() is very expensive, and chances are this
1621 			// call is unnecessary, but because of the design of the graphics class we
1622 			// have no way of knowing
1623 			SelectObject(printHDC, hOldFont);
1624 		}
1625 
1626 		m_xhdc = printHDC;
1627 		m_yhdc = printHDC;
1628 	}
1629 }
1630 
newFont(LOGFONTW & lf,double fPoints,HDC hdc,HDC printHDC)1631 GR_Win32Font * GR_Win32Font::newFont(LOGFONTW &lf, double fPoints, HDC hdc, HDC printHDC)
1632 {
1633 	GR_Win32Font * f = new GR_Win32Font(lf, fPoints, hdc, printHDC);
1634 
1635 	if(!f || !f->getFontHandle())
1636 	{
1637 		delete f;
1638 		f = NULL;
1639 	}
1640 
1641 	return f;
1642 }
1643 
1644 
~GR_Win32Font()1645 GR_Win32Font::~GR_Win32Font()
1646 {
1647 	// We currently can't delete the font, since it might
1648 	// be selected into a DC. Also, we don't keep track of previously
1649 	// selected font [into the DC] why it's impossible to revert to that
1650 	// one! :-<
1651 	// But, let's try it like this...
1652 	//
1653 	// the GetObjectType call with 0 throws a first chance exception
1654 	// (this whole thing is rather messy)
1655 
1656 	DWORD dwObjType;
1657 	bool bIsDC = false;
1658 
1659 	if(m_hdc)
1660 	{
1661 		dwObjType = GetObjectType((HGDIOBJ)m_hdc);
1662 		bIsDC = (dwObjType == OBJ_DC || dwObjType == OBJ_MEMDC);
1663 	}
1664 
1665 	for (UT_sint32 i = 0; i < m_allocFonts.getItemCount(); ++i)
1666 	  {
1667 		  allocFont *p = (allocFont *)m_allocFonts.getNthItem(i);
1668 
1669 		  if(m_hdc)
1670 		  {
1671 			  if (!bIsDC || p->hFont != (HFONT)::GetCurrentObject(m_hdc, OBJ_FONT))
1672 			  {
1673 				  DeleteObject(p->hFont);
1674 			  }
1675 		  }
1676 
1677 		  delete p;
1678 	  }
1679 }
1680 
1681 /*!
1682     hdc -- handle to the primary DC on which we draw
1683     printHDC -- handle to the DC on which we want to measure the font (typically the printer)
1684                 can be NULL (in which case hdc will be used
1685 
1686     NB: the caller must ensure that the corresponding HFONT is already selected onto the
1687     DC represented by printHDC (or hdc if NULL).
1688 */
_updateFontYMetrics(HDC hdc,HDC printHDC)1689 void GR_Win32Font::_updateFontYMetrics(HDC hdc, HDC printHDC)
1690 {
1691 	// have to have at least the prinary DC
1692 	UT_return_if_fail( hdc );
1693 
1694 	// only do this if we have reason to believe the cached values are stale
1695 	if(!printHDC)
1696 	{
1697 		printHDC = hdc;
1698 	}
1699 
1700 	// we have to remeasure if (a) the printer changed, or (b) the primary device changed
1701 	if(printHDC != m_yhdc)
1702 	{
1703 		GetTextMetricsW(printHDC,&m_tm);
1704 
1705 		// now we have to scale the metrics down from the printHDC to our layout units
1706 		//
1707 		// (we used to scale the metrics down to the device resolution, but that since we
1708 		// then scale it back up to layout units all the time, this caused us huge
1709 		// rounding error) Tomas, 16/9/05
1710 		//
1711 		// NB: we do not want to obtain the metrics directly for the primary dc
1712 		// Windows is designed to get slightly bigger font for the screen than the
1713 		// user asks for (MS say to improve readibility), and this causes us
1714 		// non-WYSIWYG behaviour (basically our characters are wider on screen than on
1715 		// the printer and our lines are further apart)
1716 		int nLogPixelsY      = GR_Graphics::getResolution();
1717 		int nPrintLogPixelsY = GetDeviceCaps(printHDC, LOGPIXELSY);
1718 
1719 		if(nLogPixelsY != nPrintLogPixelsY)
1720 		{
1721 			m_tm.tmAscent  = MulDiv(m_tm.tmAscent, nLogPixelsY, nPrintLogPixelsY);
1722 			m_tm.tmDescent = MulDiv(m_tm.tmDescent, nLogPixelsY, nPrintLogPixelsY);
1723 			m_tm.tmHeight  = MulDiv(m_tm.tmHeight, nLogPixelsY, nPrintLogPixelsY);
1724 		}
1725 
1726 		// now remember what HDC these values are for
1727 		m_yhdc = printHDC;
1728 	}
1729 }
1730 
1731 
1732 /*! hdc - handle to device context for which the measurment is required */
getAscent(HDC hdc,HDC printHDC)1733 UT_uint32 GR_Win32Font::getAscent(HDC hdc, HDC printHDC)
1734 {
1735 	if(!m_bGUIFont)
1736 		_updateFontYMetrics(hdc, printHDC);
1737 	return m_tm.tmAscent;
1738 }
1739 
1740 /*! hdc - handle to device context for which the measurment is required */
getDescent(HDC hdc,HDC printHDC)1741 UT_uint32 GR_Win32Font::getDescent(HDC hdc, HDC printHDC)
1742 {
1743 	if(!m_bGUIFont)
1744 		_updateFontYMetrics(hdc, printHDC);
1745 	return m_tm.tmDescent;
1746 }
1747 
1748 /*! hdc - handle to device context for which the measurment is required */
getHeight(HDC hdc,HDC printHDC)1749 UT_uint32 GR_Win32Font::getHeight(HDC hdc, HDC printHDC)
1750 {
1751 	if(!m_bGUIFont)
1752 		_updateFontYMetrics(hdc, printHDC);
1753 	return m_tm.tmHeight;
1754 }
1755 
1756 
measureUnremappedCharForCache(UT_UCSChar cChar) const1757 UT_sint32 GR_Win32Font::measureUnremappedCharForCache(UT_UCSChar cChar) const
1758 {
1759 #ifndef ABI_GRAPHICS_PLUGIN_NO_WIDTHS
1760 	// first of all, handle 0-width spaces ...
1761 	if(cChar == 0xFEFF || cChar == 0x200b || cChar == UCS_LIGATURE_PLACEHOLDER)
1762 		return 0;
1763 
1764 	// this function is only called when there is no value in the
1765 	// cache; we will set not only the value for the character
1766 	// required, but also for everything on the same char-width page
1767     UT_return_val_if_fail(_getCharWidths(),0);
1768 
1769 	// calculate the limits of the 256-char page
1770 	UT_UCS4Char base = (cChar & 0xffffff00);
1771 	UT_UCS4Char limit = (cChar | 0x000000ff);
1772 	HDC hdc = CreateDCW(L"DISPLAY",NULL,NULL,NULL);
1773 	SelectObject(hdc,m_layoutFont);
1774 	_getCharWidths()->setCharWidthsOfRange(hdc, base, limit);
1775 	DeleteDC(hdc);
1776 	return _getCharWidths()->getWidth(cChar);
1777 #else
1778 	UT_return_val_if_fail(UT_NOT_IMPLEMENTED,0);
1779 #endif
1780 }
1781 
1782 /*!
1783     UT_Rect of glyph in Logical units.
1784 	rec.left = bearing Left (distance from origin to start)
1785 	rec.width = width of the glyph
1786 	rec.top = distance from the origin to the top of the glyph
1787 	rec.height = total height of the glyph
1788 
1789     This function will only work on win NT -- check the return value before doing anything
1790     with the rectangle (win9x implementation would have to use GetGlyphOutlineA() and
1791     convert the UT_UCS4Char to an appropriate ansi value
1792 */
glyphBox(UT_UCS4Char g,UT_Rect & rec,GR_Graphics * pG)1793 bool GR_Win32Font::glyphBox(UT_UCS4Char g, UT_Rect & rec, GR_Graphics * pG)
1794 {
1795 	UT_return_val_if_fail( pG, false );
1796 	GR_Win32Graphics * pWin32Gr = (GR_Win32Graphics *)pG;
1797 
1798 	// we do all measurements on the printer DC and only later scale down to display to
1799 	// ensure WYSIWYG behaviour
1800 	HDC hdc = getPrimaryHDC();
1801 	HDC printDC = pWin32Gr->getPrintDC() ? pWin32Gr->getPrintDC() : hdc;
1802 
1803 	GLYPHMETRICS gm;
1804 	MAT2 m = {{0,1}, {0,0}, {0,0}, {0,1}};
1805 
1806 	int nPrintLogPixelsY = GetDeviceCaps(printDC, LOGPIXELSY);// resolution of printer
1807 	int nPrintLogPixelsX = GetDeviceCaps(printDC, LOGPIXELSX);
1808 
1809 	UT_uint32 pixels = getUnscaledHeight();
1810 
1811 	// scale the pixel size to the printer resolution and get the font
1812 	if(!m_bGUIFont)
1813 	{
1814 		// use point size to reduce rounding errors
1815 		// pixels = MulDiv(pixels, nPrintLogPixelsY, 72);
1816 		pixels = (int)(m_fPointSize * (double)nPrintLogPixelsY / 72.0 + 0.5);
1817 	}
1818 
1819 	HFONT pFont = getFontFromCache(pixels, false, 100);
1820 	if (!pFont)
1821 	{
1822 		fetchFont(pixels);
1823 		pFont = getFontFromCache(pixels, false, 100);
1824 	}
1825 
1826 	// select our font into the printer DC
1827 	HGDIOBJ hRet = SelectObject(printDC, pFont);
1828 	UT_return_val_if_fail( hRet != (void*)GDI_ERROR, false);
1829 
1830 	// remember which font we selected into the dc
1831 	if(printDC == pWin32Gr->getPrintDC())
1832 		pWin32Gr->setPrintDCFontAllocNo(getAllocNumber());
1833 
1834 	if(printDC == pWin32Gr->getPrimaryDC())
1835 		pWin32Gr->setDCFontAllocNo(getAllocNumber());
1836 
1837 	DWORD iRet = GDI_ERROR;
1838 
1839 	if (UT_IsWinNT())
1840 	{
1841 		iRet = GetGlyphOutlineW(printDC, (UINT)g, GGO_METRICS, &gm, 0, NULL, &m);
1842 	}
1843 	else
1844 	{
1845 		// GetGlyphOutlineA() ... using the GGO_GLYPH_INDEX = 0x0080 to get the ttf glyph
1846 		// for the unicode character set in ANSI
1847 
1848 		// first of all, we need to translate the ucs4 value to the index; we use
1849 		// GetCharacterPlacementW() for this. Event though the docs state that this
1850 		// function is only available on win9x via unicows, this is in fact incorrect
1851 		// (whether the 9x version of the function is fully functional I do not know, but
1852 		// it does glyph index lookup).
1853 		UINT iIndx;
1854 		GCP_RESULTSW gcpResult;
1855 		memset(&gcpResult, 0, sizeof(gcpResult));
1856 
1857 		gcpResult.lStructSize = sizeof(GCP_RESULTS);
1858 
1859 		// w32api changed lpGlyphs from UINT * to LPWSTR to match MS PSDK in w32api v2.4
1860 #if defined(__MINGW32__) && (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION < 4)
1861 		gcpResult.lpGlyphs = (UINT *) &iIndx;	// Character glyphs
1862 #else
1863 		gcpResult.lpGlyphs = (LPWSTR) &iIndx;	// Character glyphs
1864 #endif
1865 		gcpResult.nGlyphs = 1;  // Array size
1866 
1867 		if(GetCharacterPlacementW(printDC, (LPCWSTR)&g, 1, 0, &gcpResult, 0))
1868 		{
1869 			iRet = GetGlyphOutlineA(printDC, iIndx, 0x0080 | GGO_METRICS, &gm, 0, NULL, &m);
1870 		}
1871 		else
1872 		{
1873 			// OK, the GetCharacterPlacementW function probably not present, we just do
1874 			// our best with the ANSI stuff
1875 			iRet = GetGlyphOutlineA(printDC, g, GGO_METRICS, &gm, 0, NULL, &m);
1876 		}
1877 	}
1878 
1879 	if(GDI_ERROR == iRet)
1880 		return false;
1881 
1882 	rec.left   = gm.gmptGlyphOrigin.x;
1883 	rec.top    = gm.gmptGlyphOrigin.y;
1884 	rec.width  = gm.gmBlackBoxX;
1885 	rec.height = gm.gmBlackBoxY;
1886 
1887 	// the metrics are in device units, scale them to layout
1888 	int iResolution = pG->getResolution();
1889 	rec.height  = MulDiv(rec.height, iResolution, nPrintLogPixelsY);
1890 	rec.top  = MulDiv(rec.top, iResolution, nPrintLogPixelsY);
1891 
1892 	rec.width  = MulDiv(rec.width, iResolution, nPrintLogPixelsX);
1893 	rec.left  = MulDiv(rec.left, iResolution, nPrintLogPixelsX);
1894 
1895 	UT_DEBUGMSG(("gr_Win32Graphics::glyphBox(l=%d, t=%d, w=%d, h=%d\n", rec.left, rec.top, rec.width, rec.height));
1896 	return true;
1897 }
1898 
1899 /*!
1900 	Implements a GR_CharWidths.
1901 	Override if you which to instanciate a subclass.
1902  */
newFontWidths(void) const1903 GR_CharWidths* GR_Win32Font::newFontWidths(void) const
1904 {
1905 #ifndef ABI_GRAPHICS_PLUGIN_NO_WIDTHS
1906 	return new GR_Win32CharWidths();
1907 #else
1908 	UT_return_val_if_fail(UT_NOT_IMPLEMENTED,NULL);
1909 #endif
1910 }
1911 
getFontFromCache(UT_uint32 pixelsize,bool,UT_uint32) const1912 HFONT GR_Win32Font::getFontFromCache(UT_uint32 pixelsize, bool /*bIsLayout*/, UT_uint32 /*zoomPercentage*/) const
1913 {
1914 	UT_uint32 l = 0;
1915 	UT_uint32 count = m_allocFonts.getItemCount();
1916 	allocFont *entry;
1917 
1918 	while (l < count)
1919 	  {
1920 		  entry = (allocFont *)m_allocFonts.getNthItem(l);
1921 		  if (entry && entry->pixelSize == pixelsize)
1922 			  return entry->hFont;
1923 		  l++;
1924 	  }
1925 
1926 	return NULL;
1927 }
1928 
insertFontInCache(UT_uint32 pixelsize,HFONT pFont) const1929 void GR_Win32Font::insertFontInCache(UT_uint32 pixelsize, HFONT pFont) const
1930 {
1931 	allocFont *entry = new allocFont;
1932 	entry->pixelSize = pixelsize;
1933 	entry->hFont = pFont;
1934 
1935 	m_allocFonts.push_back(static_cast<void *>(entry));
1936 }
1937 
fetchFont(UT_uint32 pixelsize) const1938 void GR_Win32Font::fetchFont(UT_uint32 pixelsize) const
1939 {
1940 	LOGFONTW lf;
1941 
1942 	GetObjectW(m_layoutFont, sizeof(LOGFONTW), &lf);
1943 	lf.lfHeight = pixelsize;
1944 
1945 	if (lf.lfHeight>0) lf.lfHeight = - lf.lfHeight;
1946 
1947 	HFONT pFont = CreateFontIndirectW(&lf);
1948 
1949 	insertFontInCache(pixelsize, pFont);
1950 }
1951 
getDisplayFont(GR_Graphics * pG)1952 HFONT GR_Win32Font::getDisplayFont(GR_Graphics * pG)
1953 {
1954 	UT_uint32 zoom = m_bGUIFont ? 100 : pG->getZoomPercentage();
1955 	UT_uint32 pixels = m_bGUIFont ? m_iHeight : m_iHeight*zoom/100;
1956 
1957 	HFONT pFont = getFontFromCache(pixels, false, zoom);
1958 	if (pFont)
1959 		return pFont;
1960 
1961 	fetchFont(pixels);
1962 	return getFontFromCache(pixels, false, zoom);
1963 }
1964 
measureUnRemappedChar(UT_UCSChar c,UT_uint32 *)1965 UT_sint32 GR_Win32Font::measureUnRemappedChar(UT_UCSChar c, UT_uint32 * /*height*/)
1966 {
1967 #ifndef ABI_GRAPHICS_PLUGIN_NO_WIDTHS
1968 	// first of all, handle 0-width spaces ...
1969 	if(c == 0xFEFF || c == 0x200b || c == UCS_LIGATURE_PLACEHOLDER)
1970 		return 0;
1971 
1972 	UT_sint32 iWidth = getCharWidthFromCache(c);
1973 	return iWidth;
1974 #else
1975 	UT_return_val_if_fail(UT_NOT_IMPLEMENTED,0);
1976 #endif
1977 }
1978 
selectFontIntoDC(GR_Graphics * pGr,HDC hdc)1979 void GR_Win32Font::selectFontIntoDC(GR_Graphics * pGr, HDC hdc)
1980 {
1981 	HFONT hFont = getDisplayFont(pGr);
1982 	UT_DebugOnly<HGDIOBJ> hRet = SelectObject(hdc, hFont);
1983 
1984 	// hate having to do the cast, here
1985 	UT_ASSERT_HARMLESS( hRet != (void*)GDI_ERROR);
1986 }
1987 
polygon(UT_RGBColor & c,UT_Point * pts,UT_uint32 nPoints)1988 void GR_Win32Graphics::polygon(UT_RGBColor& c,UT_Point *pts,UT_uint32 nPoints)
1989 {
1990 	HPEN hPen = CreatePen(PS_SOLID, (UT_sint32)((double)_tduR(m_iLineWidth) * m_fXYRatio), RGB(c.m_red, c.m_grn, c.m_blu));
1991 	HPEN hOldPen = (HPEN)SelectObject(m_hdc,hPen);
1992 
1993 	HBRUSH hBrush = CreateSolidBrush(RGB(c.m_red, c.m_grn, c.m_blu));
1994 	HBRUSH hOldBrush = (HBRUSH)SelectObject(m_hdc, hBrush);
1995 
1996 	POINT * points = new POINT[nPoints];
1997 	UT_ASSERT(points);
1998 
1999 	for (UT_uint32 i = 0; i < nPoints; ++i)
2000 	{
2001 		points[i].x = (UT_sint32)((double)_tduX(pts[i].x) * m_fXYRatio);
2002 		points[i].y = _tduY(pts[i].y);
2003 	}
2004 
2005 	Polygon(m_hdc, points, nPoints);
2006 
2007 	(void) SelectObject(m_hdc, hOldBrush);
2008 	DeleteObject(hBrush);
2009 
2010 	(void) SelectObject(m_hdc, hOldPen);
2011 	DeleteObject(hPen);
2012 
2013 	delete[] points;
2014 }
2015 
_setTransform(const GR_Transform &)2016 bool GR_Win32Graphics::_setTransform(const GR_Transform & /*tr*/)
2017 {
2018 #if 0
2019 	if(UT_IsWinNT())
2020 	{
2021 		XFORM xForm;
2022 		float fScale = static_cast<float>(static_cast<float>(tlu(1)) * static_cast<float>(getZoomPercentage()) / 100.0);
2023 
2024 		xForm.eM11 = (float)(tr.getM11() * fScale);
2025 		xForm.eM12 = (float)tr.getM12();
2026 		xForm.eM21 = (float)tr.getM21();
2027 		xForm.eM22 = (float)(tr.getM22() * fScale);
2028 		xForm.eDx  = (float)(tr.getDx());
2029 		xForm.eDy  = (float)(tr.getDy());
2030 
2031 		bool ret = (SetWorldTransform(m_hdc, & xForm) != 0);
2032 		UT_ASSERT( ret );
2033 		return ret;
2034 	}
2035 	else
2036 	{
2037 		// world tranforms are not supported, fiddle with the view
2038 		// port, etc
2039 		UT_sint32 iScale = static_cast<UT_sint32>((static_cast<float>(tlu(1)) * static_cast<float>(getZoomPercentage())/100.0);
2040 
2041 		bool res = (SetWindowExtEx(m_hdc, iScale, iScale, NULL) != 0);
2042 		UT_ASSERT( res );
2043 
2044 		if(res)
2045 		{
2046 			res = (SetViewportExtEx(m_hdc,
2047 									GetDeviceCaps(m_hdc, LOGPIXELSX),
2048 									GetDeviceCaps(m_hdc, LOGPIXELSY),
2049 									NULL) != 0);
2050 			UT_ASSERT( res );
2051 		}
2052 
2053 		// change of origins is not implemented yet
2054 		UT_ASSERT(!tr.getDx() && !tr.getDy());
2055 
2056 		return res;
2057 	}
2058 #else
2059 	return true;
2060 #endif
2061 }
2062 
2063 
saveRectangle(UT_Rect & r,UT_uint32 iIndx)2064 void GR_Win32Graphics::saveRectangle(UT_Rect & r, UT_uint32 iIndx)
2065 {
2066 	UT_Rect * oldR = NULL;
2067 	m_vSaveRect.setNthItem(iIndx, (void*)new UT_Rect(r),(const void **)&oldR);
2068 	DELETEP(oldR);
2069 
2070 	UT_uint32 iWidth = (UT_sint32)((double)_tduR(r.width) * m_fXYRatio);
2071 	UT_uint32 iHeight = _tduR(r.height);
2072 	UT_sint32 x = (UT_sint32)((double)_tduX(r.left) * m_fXYRatio);
2073 	UT_sint32 y = _tduY(r.top);
2074 
2075 	#ifdef GR_GRAPHICS_DEBUG
2076 	UT_DEBUGMSG(("GR_Win32Graphics::saveRectangle %u, %u %u %u %u\n", iIndx,
2077 		x,y, iWidth, iHeight));
2078 	#endif
2079 
2080 	BITMAPINFO bmi;
2081 
2082 	BYTE *imagedata;
2083 	HDC	hMemDC = CreateCompatibleDC(m_hdc);
2084 
2085 	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2086 	bmi.bmiHeader.biWidth = iWidth;
2087 	bmi.bmiHeader.biHeight = iHeight;
2088 	bmi.bmiHeader.biPlanes = 1;
2089 	bmi.bmiHeader.biBitCount = 24; // as we want true-color
2090 	bmi.bmiHeader.biCompression = BI_RGB; // no compression
2091 	bmi.bmiHeader.biSizeImage = (((iWidth * bmi.bmiHeader.biBitCount + 31) & ~31) >> 3) * iHeight;
2092 	bmi.bmiHeader.biXPelsPerMeter = 0;
2093 	bmi.bmiHeader.biYPelsPerMeter = 0;
2094 	bmi.bmiHeader.biClrImportant = 0;
2095 	bmi.bmiHeader.biClrUsed = 0; // we are not using palette
2096 
2097 	HBITMAP hBit = CreateDIBSection(hMemDC,&bmi,DIB_RGB_COLORS,(void**)&imagedata,0,0);
2098 	GdiFlush();
2099 
2100 	HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBit);
2101 	BitBlt(hMemDC, 0, 0, iWidth, iHeight, m_hdc, x, y, SRCCOPY);
2102 	hBit =  (HBITMAP)SelectObject(hMemDC, hOld);
2103 	DeleteDC(hMemDC);
2104 
2105 	m_vSaveRectBuf.setNthItem(iIndx, (void*) hBit, (const void**)&hOld);
2106 	DeleteObject(hOld);
2107 }
2108 
restoreRectangle(UT_uint32 iIndx)2109 void GR_Win32Graphics::restoreRectangle(UT_uint32 iIndx)
2110 {
2111 	UT_Rect * r = (UT_Rect*)m_vSaveRect.getNthItem(iIndx);
2112 	HBITMAP hBit = (HBITMAP)m_vSaveRectBuf.getNthItem(iIndx);
2113 
2114 	UT_return_if_fail(r);
2115 	UT_ASSERT(hBit);
2116 
2117 	UT_uint32 iWidth = (UT_sint32)((double)_tduR(r->width) * m_fXYRatio);
2118 	UT_uint32 iHeight = _tduR(r->height);
2119 	UT_sint32 x = (UT_sint32)((double)_tduX(r->left) * m_fXYRatio);
2120 	UT_sint32 y = _tduY(r->top);
2121 
2122 	#ifdef GR_GRAPHICS_DEBUG
2123 	UT_DEBUGMSG(("GR_Win32Graphics::restoreRectangle %u, %u %u %u %u\n", iIndx,
2124 		x,y, iWidth, iHeight));
2125 	#endif
2126 
2127 	HDC		hMemDC = CreateCompatibleDC(m_hdc);
2128 	HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBit);
2129 
2130 	BitBlt(m_hdc, x, y, iWidth, iHeight, hMemDC, 0, 0, SRCCOPY);
2131 	SelectObject(hMemDC, hOld);
2132 	DeleteDC(hMemDC);
2133 }
2134 
flush(void)2135 void GR_Win32Graphics::flush(void)
2136 {
2137 	GdiFlush();
2138 }
2139 
2140 //--------------------------------------------------------------------------/
2141 //--------------------------------------------------------------------------/
2142 
ConvertDDBToDIB(HBITMAP bitmap,HPALETTE hPal,DWORD dwCompression)2143 BITMAPINFO * GR_Win32Graphics::ConvertDDBToDIB(HBITMAP bitmap, HPALETTE hPal, DWORD dwCompression) {
2144 
2145 	BITMAP				bm;
2146 	BITMAPINFOHEADER	bi;
2147 	LPBITMAPINFOHEADER 	lpbi;
2148 	DWORD				dwLen;
2149 	HANDLE				hDIB;
2150 	HANDLE				handle;
2151 	HDC 				hDC;
2152 
2153 	if (dwCompression == BI_BITFIELDS)
2154 		return NULL;
2155 
2156 	if (hPal == NULL)
2157 		hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
2158 
2159 	// Get bitmap information
2160 	::GetObjectW(bitmap, sizeof(bm),(LPSTR)&bm);
2161 
2162 	// Initialize the bitmapinfoheader
2163 	bi.biSize			= sizeof(BITMAPINFOHEADER);
2164 	bi.biWidth			= bm.bmWidth;
2165 	bi.biHeight 		= bm.bmHeight;
2166 	bi.biPlanes 		= 1;
2167 	bi.biBitCount		= bm.bmPlanes * bm.bmBitsPixel;
2168 	bi.biCompression	= dwCompression;
2169 	bi.biSizeImage		= 0;
2170 	bi.biXPelsPerMeter	= 0;
2171 	bi.biYPelsPerMeter	= 0;
2172 	bi.biClrUsed		= 0;
2173 	bi.biClrImportant	= 0;
2174 
2175 	// Compute the size of the  infoheader and the color table
2176 	int nColors = (1 << bi.biBitCount);
2177 	if( nColors > 256 )
2178 		nColors = 0;
2179 	dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);
2180 
2181 	// We need a device context to get the DIB from
2182 	hDC = CreateCompatibleDC(m_hdc);
2183 	hPal = SelectPalette(hDC, hPal, TRUE);
2184 	RealizePalette(hDC);
2185 
2186 	// Allocate enough memory to hold bitmapinfoheader and color table
2187 	hDIB = g_try_malloc(dwLen);
2188 	if (!hDIB){
2189 		SelectPalette(hDC, hPal, TRUE);
2190 		DeleteDC(hDC);
2191 		return NULL;
2192 		}
2193 	lpbi = (LPBITMAPINFOHEADER)hDIB;
2194 	*lpbi = bi;
2195 
2196 	// Call GetDIBits with a NULL lpBits param, so the device driver
2197 	// will calculate the biSizeImage field
2198 	GetDIBits(
2199 		hDC,
2200 		bitmap,
2201 		0L,
2202 		(DWORD)bi.biHeight,
2203 		(LPBYTE)NULL,
2204 		(LPBITMAPINFO)lpbi,
2205 		(DWORD)DIB_RGB_COLORS
2206 		);
2207 	bi = *lpbi;
2208 
2209 	// If the driver did not fill in the biSizeImage field, then compute it
2210 	// Each scan line of the image is aligned on a DWORD (32bit) boundary
2211 	if (bi.biSizeImage == 0) {
2212 		bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;
2213 
2214 		// If a compression scheme is used the result may infact be larger
2215 		// Increase the size to account for this.
2216 		if (dwCompression != BI_RGB)
2217 			bi.biSizeImage = (bi.biSizeImage * 3) / 2;
2218 		}
2219 
2220 	// Realloc the buffer so that it can hold all the bits
2221 	dwLen += bi.biSizeImage;
2222 	handle = g_try_realloc(hDIB, dwLen);
2223 	if (handle)
2224 		hDIB = handle;
2225 	else{
2226 		g_free(hDIB);
2227 		// Reselect the original palette
2228 		SelectPalette(hDC,hPal,TRUE);
2229 		DeleteDC(hDC);
2230 		return NULL;
2231 		}
2232 
2233 	// Get the bitmap bits
2234 	lpbi = (LPBITMAPINFOHEADER)hDIB;
2235 
2236 	// FINALLY get the DIB
2237 	BOOL bGotBits = GetDIBits(
2238 		hDC,
2239 		bitmap,
2240 		0L,							// Start scan line
2241 		(DWORD)bi.biHeight,			// # of scan lines
2242 		(LPBYTE)lpbi 				// address for bitmap bits
2243 		+ (bi.biSize + nColors * sizeof(RGBQUAD)),
2244 		(LPBITMAPINFO)lpbi,			// address of bitmapinfo
2245 		(DWORD)DIB_RGB_COLORS		// Use RGB for color table
2246 		);
2247 
2248 	if (!bGotBits)	{
2249 		g_free(hDIB);
2250 		SelectPalette(hDC,hPal,TRUE);
2251 		DeleteDC(hDC);
2252 		return NULL;
2253 		}
2254 
2255 	SelectPalette(hDC,hPal,TRUE);
2256 	DeleteDC(hDC);
2257 
2258 	return (BITMAPINFO*)hDIB;
2259 	}
2260 
2261 //--------------------------------------------------------------------------/
2262 //--------------------------------------------------------------------------/
2263 
genImageFromRectangle(const UT_Rect & r)2264 GR_Image * GR_Win32Graphics::genImageFromRectangle(const UT_Rect & r) {
2265 
2266 	UT_uint32 iWidth = (UT_sint32)((double)tdu(r.width) * m_fXYRatio);
2267 	UT_uint32 iHeight = tdu(r.height);
2268 	UT_sint32 x = (UT_sint32)((double)tdu(r.left) * m_fXYRatio);
2269 	UT_sint32 y = tdu(r.top);
2270 
2271 	UT_return_val_if_fail((iWidth > 0) && (iHeight > 0) && (y >= 0) && (x >= 0), NULL);
2272 
2273 	BITMAPINFO bmi;
2274 	BYTE *imagedata;
2275 	HDC hMemDC = CreateCompatibleDC(m_hdc);
2276 
2277 	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
2278 	bmi.bmiHeader.biWidth = iWidth;
2279 	bmi.bmiHeader.biHeight = iHeight;
2280 	bmi.bmiHeader.biPlanes = 1;
2281 	bmi.bmiHeader.biBitCount = 24; // as we want true-color
2282 	bmi.bmiHeader.biCompression = BI_RGB; // no compression
2283 	bmi.bmiHeader.biSizeImage = (((iWidth * bmi.bmiHeader.biBitCount + 31) & ~31) >> 3) * iHeight;
2284 	bmi.bmiHeader.biXPelsPerMeter = 0;
2285 	bmi.bmiHeader.biYPelsPerMeter = 0;
2286 	bmi.bmiHeader.biClrImportant = 0;
2287 	bmi.bmiHeader.biClrUsed = 0; // we are not using palette
2288 
2289 	HBITMAP hBit = CreateDIBSection(hMemDC,&bmi,DIB_RGB_COLORS,(void**)&imagedata,0,0);
2290 
2291 	GdiFlush();
2292 
2293 	HBITMAP hOld = (HBITMAP) SelectObject(hMemDC, hBit);
2294 		BitBlt(hMemDC, 0, 0, iWidth, iHeight, m_hdc, x, y, SRCCOPY);
2295 		hBit =  (HBITMAP)SelectObject(hMemDC, hOld);
2296 	DeleteDC(hMemDC);
2297 
2298 
2299 	GR_Win32Image *img = new GR_Win32Image("Screenshot");
2300 	img->setDIB((BITMAPINFO *)ConvertDDBToDIB(hBit, NULL, BI_RGB));
2301 	return img;
2302 	}
2303 
2304 
graphicsAllocator(GR_AllocInfo & info)2305 GR_Graphics * GR_Win32Graphics::graphicsAllocator(GR_AllocInfo &info)
2306 {
2307 #ifndef ABI_GRAPHICS_PLUGIN
2308 	UT_return_val_if_fail(info.getType() == GRID_WIN32, NULL);
2309 
2310 	GR_Win32AllocInfo &AI = (GR_Win32AllocInfo&)info;
2311 
2312 	if(AI.m_pDocInfo)
2313 	{
2314 		// printer graphics required
2315 		return new GR_Win32Graphics(AI.m_hdc, AI.m_pDocInfo, AI.m_hDevMode);
2316 	}
2317 	else
2318 	{
2319 		// screen graphics required
2320 		return new GR_Win32Graphics(AI.m_hdc, AI.m_hwnd);
2321 	}
2322 #else
2323 	UT_return_val_if_fail(UT_NOT_IMPLEMENTED,NULL);
2324 #endif
2325 }
2326 
2327 #define _test_and_cleanup(x)                    \
2328 if(!(x))                                        \
2329 {                                               \
2330     UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN ); \
2331 	goto cleanup;                               \
2332 }
2333 
getPrinterGraphics(const wchar_t * pPrinterName,const wchar_t * pDocName)2334 GR_Graphics * GR_Win32Graphics::getPrinterGraphics(const wchar_t * pPrinterName,
2335 												   const wchar_t * pDocName)
2336 {
2337 	UT_return_val_if_fail( pDocName, NULL );
2338 	GR_Win32Graphics *pGr = NULL;
2339 	HGLOBAL hDM = NULL;
2340 	HANDLE hPrinter = NULL;
2341 	LONG iBuffSize = 0;
2342 	HDC hPDC = NULL;
2343 	DOCINFOW * pDI = NULL;
2344 	PDEVMODEW pDM = NULL;
2345 
2346 	bool bFreePN = false;
2347 
2348 	// we will use '-' as a shortcut for default printer (the --print command has to have
2349 	// a parameter)
2350 	wchar_t * pPN = wcscmp(L"-", pPrinterName) == 0 ? NULL : (wchar_t *) pPrinterName;
2351 	const wchar_t * pDriver = UT_IsWinNT() ? L"WINSPOOL" : NULL;
2352 
2353 	if(!pPN)
2354 	{
2355 		pPN = UT_GetDefaultPrinterName();
2356 		bFreePN = true;
2357 	}
2358 
2359 	_test_and_cleanup(pPN);
2360 
2361 	hPDC = CreateDCW(pDriver, pPN, NULL, NULL);
2362 
2363 	_test_and_cleanup(hPDC);
2364 
2365 	_test_and_cleanup( OpenPrinterW(pPN, &hPrinter, NULL));
2366 
2367 	// first, get the size of the buffer needed for the document mode
2368 	iBuffSize = DocumentPropertiesW(NULL, hPrinter,	pPN, NULL, NULL, 0);
2369 	_test_and_cleanup( iBuffSize );
2370 
2371 	// must be global movable memory
2372 	hDM = GlobalAlloc(GHND, iBuffSize);
2373 	pDM = (PDEVMODEW)GlobalLock(hDM);
2374 	_test_and_cleanup(hDM && 0<DocumentPropertiesW(NULL, hPrinter, pPN, pDM, NULL, DM_OUT_BUFFER));
2375 	GlobalUnlock(hDM);
2376 
2377 	// we have all we need to fill in the doc info structure ...
2378 	pDI = (DOCINFOW*) UT_calloc(1, sizeof(DOCINFOW));
2379 	_test_and_cleanup(pDI);
2380 
2381 	memset(pDI, 0, sizeof(DOCINFOW));
2382 
2383 	pDI->cbSize = sizeof(DOCINFOW);
2384 	pDI->lpszDocName = pDocName;
2385 	pDI->lpszOutput  = NULL; // for now we do not support printing into file from cmd line
2386 	pDI->lpszDatatype = NULL;
2387 	pDI->fwType = 0;
2388 
2389 	{
2390 		GR_Win32AllocInfo ai(hPDC, pDI, hDM);
2391 
2392 		pGr = (GR_Win32Graphics *)XAP_App::getApp()->newGraphics(ai);
2393 		UT_ASSERT_HARMLESS(pGr);
2394 	}
2395 
2396  cleanup:
2397 	if(bFreePN)
2398 		g_free(pPN);
2399 
2400 	if(hDM && !pGr)
2401 		GlobalFree(hDM);
2402 
2403 	if(pDI && !pGr)
2404 		g_free(pDI);
2405 
2406 	if(hPrinter)
2407 		ClosePrinter(hPrinter);
2408 
2409 	return pGr;
2410 }
2411 
2412 
2413 /*!
2414     This function absolutely must be called anytime the DEVMODE structure is modified in
2415     any way; it also must be called on the DEVMODE handle returned by PringDlg. Those who
2416     will modify DEVMODE structure and not call this function on it will be shot, without
2417     exception.
2418 
2419     The issue with the DEVMODE structure is this: it consists of two parts, a public part
2420     declared by the win32 headers, and a private part, the size and contents of which
2421     depend on the printer. Before a printer can be passed the DEVMODE structure, two
2422     things have to be satisfied:
2423 
2424     1. The memory allocated for the structure has to be large enough to hold both the
2425        public and private parts of the structure; we obtain the handle from the
2426        PrintDlg, and it _should_ allocate the necessary size correctly. In any case, we
2427        cannot meddle with the size, since reallocating means loosing the private part.
2428 
2429     2. The settings represented by the public part have to be transferred into the private
2430        part; this is achieved by calling the DocumentProperties() function on the
2431        structure. So any time we modify the contents of DEVMODE in any way we have to call
2432        DocumentProperties() before we can pass the pointer / handle to any other
2433        function. In addition, I have a strong suspicion that the PrintDlg function only
2434        sets the public section, but does not call DocumentProperties(), so we have to do
2435        that ourselves once we get the handle back.
2436 */
fixDevMode(HGLOBAL hDevMode)2437 bool GR_Win32Graphics::fixDevMode(HGLOBAL hDevMode)
2438 {
2439 	DEVMODEW * pDM = (DEVMODEW*)GlobalLock(hDevMode);
2440 	UT_return_val_if_fail( pDM, false );
2441 
2442 	// find out how big structure this particular printer really needs
2443 	HANDLE      hPrinter;
2444 	DWORD       dwNeeded, dwRet;
2445 
2446 	//Start by opening the printer
2447 	if(!OpenPrinterW((wchar_t*)& pDM->dmDeviceName, &hPrinter, NULL))
2448 	{
2449 		UT_String msg;
2450 		UT_String_sprintf(msg,"Unable to open printer [%s]", (char*)& pDM->dmDeviceName);
2451 		LOG_WIN32_EXCPT(msg.c_str());
2452 		GlobalUnlock(hDevMode);
2453 		UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
2454 		return false;
2455 	}
2456 
2457 	dwNeeded = DocumentPropertiesW(NULL,hPrinter, (wchar_t*)& pDM->dmDeviceName, NULL, NULL, 0);
2458 
2459 	if( (int) dwNeeded > pDM->dmSize + pDM->dmDriverExtra )
2460 	{
2461 		// we are knees deep in crap here ... log it into the users profile, so we have
2462 		// some debug info to go on
2463 		UT_String msg;
2464 		UT_String_sprintf(msg,"DEVMODE too small [%s, needs %ld, got %d + %d]",
2465 						  (char*)& pDM->dmDeviceName, dwNeeded, pDM->dmSize, pDM->dmDriverExtra);
2466 		LOG_WIN32_EXCPT(msg.c_str());
2467 		ClosePrinter(hPrinter);
2468 		GlobalUnlock(hDevMode);
2469 		UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
2470 		return false;
2471 	}
2472 
2473 	// now get the printer driver to merge the data in the public section into its private part
2474 	dwRet = DocumentPropertiesW(NULL,hPrinter, (wchar_t*)& pDM->dmDeviceName, pDM, pDM, DM_OUT_BUFFER | DM_IN_BUFFER);
2475 
2476 	// g_free what needs be ...
2477 	ClosePrinter(hPrinter);
2478 	GlobalUnlock(hDevMode);
2479 
2480 	UT_return_val_if_fail( dwRet == IDOK, false );
2481 	return true;
2482 }
2483 
getDocInfo()2484 DOCINFOW *GR_Win32Graphics::getDocInfo()
2485 {
2486   DOCINFOW *di;
2487 
2488   di = (DOCINFOW*) UT_calloc(1, sizeof(DOCINFOW));
2489   memset( di, 0, sizeof(DOCINFOW) );
2490   di->cbSize = sizeof(DOCINFOW);
2491   di->lpszDocName = L"AbiWord Print Preview";
2492   di->lpszOutput = (LPWSTR) NULL;
2493   di->lpszDatatype = (LPWSTR) NULL;
2494   di->fwType = 0;
2495 
2496   return di;
2497 }
2498 
2499 /*
2500  *  Creates a HDC to the best printer to be used as a reference for CreateEnhMetaFile
2501  */
createbestmetafilehdc()2502 HDC GR_Win32Graphics::createbestmetafilehdc()
2503 {
2504   DWORD neededsize;
2505   DWORD noprinters;
2506   LPPRINTER_INFO_5W printerinfo = NULL;
2507   int bestres = 0;
2508   HDC besthdc = 0;
2509 
2510   if (EnumPrintersW(PRINTER_ENUM_CONNECTIONS|PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0,
2511 		&neededsize, &noprinters))
2512   {
2513 	printerinfo = (LPPRINTER_INFO_5W) malloc(neededsize);
2514   } else {
2515 	return GetDC(NULL);
2516   }
2517 
2518   if (EnumPrintersW(PRINTER_ENUM_CONNECTIONS|PRINTER_ENUM_LOCAL, NULL, 5,
2519 		   (LPBYTE)printerinfo, neededsize, &neededsize, &noprinters)) {
2520     // init best resolution for hdc=0, which is screen resolution:
2521     HDC curhdc = GetDC(NULL);
2522     if (curhdc) {
2523       bestres = GetDeviceCaps(curhdc, LOGPIXELSX) + GetDeviceCaps(curhdc,
2524 								  LOGPIXELSY);
2525       bestres = ReleaseDC(NULL, curhdc);
2526     }
2527 
2528     for (UT_uint32 i = 0; i < noprinters; i++) {
2529       curhdc = CreateDCW(L"WINSPOOL", printerinfo[i].pPrinterName, NULL, NULL);
2530       if (curhdc) {
2531 	int curres = GetDeviceCaps(curhdc, LOGPIXELSX) + GetDeviceCaps(curhdc,
2532 								       LOGPIXELSY);
2533 	if (curres > bestres) {
2534 	  if (besthdc)
2535 	    DeleteDC(besthdc);
2536 	  bestres = curres;
2537 	  besthdc = curhdc;
2538 	} else {
2539 	  DeleteDC(curhdc);
2540 	}
2541       }
2542     }
2543   } else return GetDC(NULL);
2544 
2545   if (printerinfo) free(printerinfo);
2546   return besthdc;
2547 }
2548 
getWidthAndHeightFromHWND(HWND h,int & width,int & height)2549 void GR_Win32Graphics::getWidthAndHeightFromHWND(HWND h, int &width, int &height)
2550 {
2551 	RECT clientRect;
2552 	GetClientRect(h, &clientRect);
2553 
2554 	width = clientRect.right - clientRect.left;
2555 	height = clientRect.bottom - clientRect.top;
2556 
2557 	UT_ASSERT(clientRect.left == 0 && clientRect.top == 0);
2558 }
2559 
_DeviceContext_MeasureBitBltCopySpeed(HDC sourceHdc,HDC destHdc,int width,int height)2560 void GR_Win32Graphics::_DeviceContext_MeasureBitBltCopySpeed(HDC sourceHdc, HDC destHdc, int width, int height)
2561 {
2562 	LARGE_INTEGER t1, t2, freq;
2563 
2564 	QueryPerformanceCounter(&t1);
2565 	BitBlt(destHdc, 0, 0, width, height, sourceHdc, 0, 0, SRCCOPY);
2566 	QueryPerformanceCounter(&t2);
2567 
2568 	QueryPerformanceFrequency(&freq);
2569 #if DEBUG
2570 	double blitSpeed = ((double)(t2.QuadPart - t1.QuadPart)) / ((double)freq.QuadPart);
2571 
2572 	UT_DEBUGMSG(("ASFRENT: measured BitBlt speed: %lfs [client rectangle W = %d, H = %d]\n",
2573 			blitSpeed, width, height));
2574 #endif
2575 }
2576 
_DeviceContext_SwitchToBuffer()2577 void GR_Win32Graphics::_DeviceContext_SwitchToBuffer()
2578 {
2579 	// get client area size
2580 	int height(0), width(0);
2581 	getWidthAndHeightFromHWND(m_hwnd, width, height);
2582 
2583 	// set up the buffer
2584 	m_bufferHdc = _DoubleBuffering_CreateBuffer(m_hdc, width, height);
2585 
2586 	// copy the screen to the buffer
2587 	BitBlt(m_bufferHdc, 0, 0, width, height, m_hdc, 0, 0, SRCCOPY);
2588 
2589 	// save the current hdc & switch
2590 	_HDCSwitchStack.push(new _HDCSwitchRecord(m_hdc));
2591 	m_hdc = m_bufferHdc;
2592 }
2593 
_DeviceContext_SwitchToScreen()2594 void GR_Win32Graphics::_DeviceContext_SwitchToScreen()
2595 {
2596 	_DeviceContext_RestorePrevHDCFromStack();
2597 
2598 	// get client area size
2599 	int height(0), width(0);
2600 	getWidthAndHeightFromHWND(m_hwnd, width, height);
2601 
2602 	// copy any modifications back to the screen
2603 	BitBlt(m_hdc, 0, 0, width, height, m_bufferHdc, 0, 0, SRCCOPY);
2604 
2605 	// free used resources
2606 	_DoubleBuffering_ReleaseBuffer(m_bufferHdc);
2607 }
2608 
_DeviceContext_RestorePrevHDCFromStack()2609 void GR_Win32Graphics::_DeviceContext_RestorePrevHDCFromStack()
2610 {
2611 	_HDCSwitchRecord *switchRecord;
2612 	_HDCSwitchStack.pop((void**)&switchRecord);
2613 	m_hdc = switchRecord->oldHdc;
2614 	delete switchRecord;
2615 }
2616 
_DeviceContext_SuspendDrawing()2617 void GR_Win32Graphics::_DeviceContext_SuspendDrawing()
2618 {
2619 	// save the current hdc & switch them!
2620 	_HDCSwitchStack.push(new _HDCSwitchRecord(m_hdc));
2621 	m_hdc = m_dummyHdc;
2622 }
2623 
_DeviceContext_ResumeDrawing()2624 void GR_Win32Graphics::_DeviceContext_ResumeDrawing()
2625 {
2626 	_DeviceContext_RestorePrevHDCFromStack();
2627 }
2628 
_DoubleBuffering_SetUpDummyBuffer()2629 void GR_Win32Graphics::_DoubleBuffering_SetUpDummyBuffer()
2630 {
2631 	m_dummyHdc = _DoubleBuffering_CreateBuffer(m_hdc, 0, 0);
2632 }
2633 
_DoubleBuffering_ReleaseDummyBuffer()2634 void GR_Win32Graphics::_DoubleBuffering_ReleaseDummyBuffer()
2635 {
2636 	_DoubleBuffering_ReleaseBuffer(m_dummyHdc);
2637 }
2638 
_DoubleBuffering_CreateBuffer(HDC compatibleWith,int width,int height)2639 HDC GR_Win32Graphics::_DoubleBuffering_CreateBuffer(HDC compatibleWith, int width, int height)
2640 {
2641 	HDC resultingHdc = CreateCompatibleDC(compatibleWith);
2642 	HBITMAP bufferBitmap = CreateCompatibleBitmap(compatibleWith, width, height);
2643 	SelectObject(resultingHdc, bufferBitmap);
2644 	return resultingHdc;
2645 }
2646 
_DoubleBuffering_ReleaseBuffer(HDC hdc)2647 void GR_Win32Graphics::_DoubleBuffering_ReleaseBuffer(HDC hdc)
2648 {
2649 	DeleteObject(GetCurrentObject(hdc, OBJ_BITMAP));
2650 	DeleteDC(hdc);
2651 }
2652