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