uLib  User mode C/C++ extended API library for Win32 programmers.
GdiUtil.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: GDI utility functions (Migrated from UtilFunc.cpp)
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib/Common.h>
9 #include <uLib/UtilFunc.h>
10 #include <uLib/Debug.h>
11 #include <uLib/StrFunc.h>
12 
13 #if 0 // Lab area..
14 #endif // Lab area..
15 
16 #if defined(_MSC_VER)
17  #define USE_GRADIENTCOLOR_ASM 1 // Use _gradcolor.asm
18  #define USE_SCALECOLOR_ASM 0 // Use C++ fallback implementation
19 #else
20  #define USE_GRADIENTCOLOR_ASM 0 // Use C++ fallback implementation
21  #define USE_SCALECOLOR_ASM 0 // Use C++ fallback implementation
22 #endif
23 
24 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 // WinGDI functions
26 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 
28 // A considerably easier way to create a font instance.
29 
30 HFONT WINAPI CreateFontEx( CSTR Typeface, int Points, int Weight, DWORD Charset, DWORD Quality )
31 {
32  Points = ScreenFontHeight( Points );
33  return ::CreateFont( Points, 0,0,0, Weight, 0,0,0, Charset,
34  OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, Quality,
35  FF_DONTCARE, Typeface
36  );
37 }
38 
39 // Compute font height to use in LOGFONT.lfHeight from size in Points.
40 // If RefDC is given, compute for that DC, else for the screen.
41 // Note: These two APIs use each other (in a careful manner).
42 
43 int WINAPI FontHeight( HDC hdc, int Points ) // Uses ScreenFontHeight
44 {
45  int height; // 1 typographic point == 1/72'th of an inch.
46 
47  if (!hdc) height = ScreenFontHeight( Points ); // Fwd recursion !
48  else height = -MulDiv( Points, GetDeviceCaps( hdc, LOGPIXELSY ),72 );
49  return height;
50 }
51 
52 int WINAPI ScreenFontHeight( WORD Points ) // Uses FontHeight
53 {
54  int height = 0;
55  HDC dc = GetDesktopDC();
56  if (dc)
57  {
58  height = FontHeight( dc, Points );
59  ReleaseDesktopDC( dc );
60  }
61  return height;
62 }
63 
64 // GetWndFont - Get the current font for hWnd..
65 
66 HFONT WINAPI GetWndFont( HWND hWnd, LOGFONT* pLogFont )
67 {
68  LOGFONT lf;
69  HDC hdc = GetDC( hWnd );
70  HFONT hfont = GetCurrentFontEx( hdc, &lf );
71  ReleaseDC( hWnd, hdc );
72  if (pLogFont) *pLogFont = lf;
73  return hfont;
74 }
75 
76 // WhereXY - Get the current drawing position in HDC
77 
78 POINT WINAPI WhereXY( HDC dc )
79 {
80  POINT xy = {0,0};
81  if (MoveToEx( dc, 0,0, &xy )) // Dummy move to get the current XY pos
82  MoveToEx( dc, xy.x, xy.y, NULL ); // Undo the move
83  return xy;
84 }
85 
86 // Release dc and return NULL if successful.
87 
88 HDC WINAPI ReleaseWndDC( HDC dc )
89 {
90  HWND wnd = WindowFromDC( dc );
91  if (wnd && ReleaseDC( wnd, dc )) dc = (HDC)NULL;
92  return dc;
93 }
94 
95 // Desktop DC
96 
97 HDC WINAPI GetDesktopDC()
98 {
99  return GetDC( GetDesktopWindow() );
100 }
101 
102 void WINAPI ReleaseDesktopDC( HDC hDeskDC )
103 {
104  ReleaseDC( GetDesktopWindow(), hDeskDC );
105 }
106 
107 // Create screen compatible memory DC and bitmap.
108 
109 HDC WINAPI CreateMemoryDC( UINT cx, UINT cy, HBITMAP* pOldBmp )
110 {
111  HDC hdc = GetDesktopDC();
112  HDC hMemDC = CreateCompatibleDC( hdc );
113  if (cx && cy && hMemDC)
114  {
115  HBITMAP hBmp = CreateCompatibleBitmap( hdc, cx, cy );
116  HBITMAP oldBmp = SelectBitmap( hMemDC, hBmp );
117  if (pOldBmp) *pOldBmp = oldBmp;
118  }
119  ReleaseDesktopDC( hdc );
120  return hMemDC;
121 }
122 
123 // Delete memory DC and return it's drawing bitmap.
124 // PONDER: Rename DeleteMemoryDC to DoneMemoryDC..?
125 
126 HBITMAP WINAPI DeleteMemoryDC( HDC hMemDC, HBITMAP oldBmp )
127 {
128  HBITMAP memBmp = (HBITMAP) GetCurrentObject( hMemDC, OBJ_BITMAP );
129  if (oldBmp)
130  {
131  oldBmp = SelectBitmap( hMemDC, oldBmp );
132  // Alert programmer if f.ex. drawing bitmap was deselected after CreateMemoryDC..
133  if (oldBmp != memBmp) DPrint( DP_WARNING, _F("oldBmp != memBmp selected in hMemDC.\n") );
134  }
135  DeleteDC( hMemDC );
136  return memBmp;
137 }
138 
139 // Get logical pixels per inch for the screen
140 
141 void WINAPI GetScreenLPI( PPOINT pLpi )
142 {
143  HDC hdc = GetDesktopDC();
144  pLpi->x = GetDeviceCaps( hdc, LOGPIXELSX );
145  pLpi->y = GetDeviceCaps( hdc, LOGPIXELSY );
146  ReleaseDesktopDC( hdc );
147 }
148 
149 // Create a bitmap from a given icon
150 
151 #if 1 // Revised to use the new CreateMemoryDC() and DeleteMemoryDC().
152 
153 HBITMAP WINAPI CreateIconBitmap( HICON hIcon, HBRUSH hbrBkg, UINT cx, UINT cy )
154 {
155  RECT r;
156  HBITMAP orgBmp;
157  if (!cx) cx = SYSMET( CXSMICON );
158  if (!cy) cy = SYSMET( CYSMICON );
159  if (!hbrBkg) hbrBkg = SYSHBR( 3DFACE );
160  HDC mdc = CreateMemoryDC( cx, cy, &orgBmp );
161 
162  SetRect( &r, 0,0, cx,cy );
163  FillRect( mdc, &r, hbrBkg );
164  DrawIconEx( mdc, 0,0, hIcon, cx,cy, 0, NULL, DI_NORMAL );
165 
166  return DeleteMemoryDC( mdc, orgBmp );
167 }
168 
169 #else // Original, plain Win32
170 HBITMAP WINAPI CreateIconBitmap( HICON hIcon, HBRUSH hbrBkg, UINT cx, UINT cy )
171 {
172  if (!cx) cx = SYSMET( CXSMICON );
173  if (!cy) cy = SYSMET( CYSMICON );
174  RECT r;
175  HDC hdc = GetDesktopDC();
176  HDC mdc = CreateCompatibleDC( hdc );
177  HBITMAP mbm = CreateCompatibleBitmap( hdc, cx, cy );
178  ReleaseDesktopDC( hdc );
179 
180  mbm = SelectBitmap( mdc, mbm ); // Swap
181  SetRect( &r, 0,0, cx,cy );
182  FillRect( mdc, &r, hbrBkg ); //SYSHBR(3DFACE) );
183  DrawIconEx( mdc, 0,0, hIcon, cx,cy, 0, NULL, DI_NORMAL );
184  mbm = SelectBitmap( mdc, mbm ); // Swap back
185 
186  DeleteDC( mdc );
187  return mbm;
188 }
189 #endif
190 
191 // CreateMaskBitmap - Create a B/W mask bitmap suitable for use with MaskBlt
192 
193 HBITMAP WINAPI CreateMaskBitmap( HBITMAP img, COLORREF transp )
194 {
195  BITMAP bim; ::GetObject( img, sizeof(BITMAP), &bim );
196  RECT r = { 0,0, bim.bmWidth, bim.bmHeight };
197 
198  HDC sdc = CreateCompatibleDC( NULL ); // Source dc
199  HBITMAP obs = (HBITMAP) SelectObject( sdc, img ); // Holds the image
200  COLORREF ocs = SetBkColor( sdc, transp ); // This voodoo does it!
201 
202  HDC mdc = CreateCompatibleDC( NULL ); // Target dc
203  HBITMAP mask = CreateBitmap( bim.bmWidth, bim.bmHeight, 1,1,NULL );
204  HBITMAP obd = (HBITMAP) SelectObject( mdc, mask ); // Now we can draw
205 
206  BitBlt( mdc, 0,0, bim.bmWidth, bim.bmHeight, sdc, 0,0, SRCCOPY ); // Make mono
207  InvertRect( mdc, &r ); // Invert the mask to satisfy standard MaskBlt.
208 
209  #if 0 // Superfluous cleaning up, since the DCs will be deleted
210  SelectObject( mdc, obd );
211  SetBkColor( sdc, ocs );
212  SelectObject( sdc, obs );
213  #endif
214  DeleteDC( mdc );
215  DeleteDC( sdc );
216 
217  return mask;
218 }
219 
220 #pragma warning( disable: 4533 ) // initialization of 'r' is skipped by 'goto __cab_Exit'
221 
222 HBITMAP WINAPI CreateAntialiasedBitmap(
223  UINT cx, UINT cy, UINT mu, PFnPaintBitmap PaintBitmap, PVOID Ctx
224  )
225 {
226  HBITMAP hBmp = NULL; // Result
227 
228  if (!PaintBitmap)
229  {
230  SetLastError( ERROR_INVALID_FUNCTION );
231  //goto __cab_Exit;
232  }
233  else
234  {
235  HBITMAP obmMem, obmTmp, hbTmp;
236  UINT _cx = mu*cx, _cy = mu*cy;
237 
238  HDC hTmpDC = CreateMemoryDC( _cx, _cy, &obmTmp );
239  RECT r = MkRect( 0,0, _cx, _cy );
240 
241  // Paint the bitmap in upscaled size..
242 
243  bool ok;
244  PAINTBMPSTRUCT ps;
245  ps.hDC = hTmpDC;
246  ps.rcPaint = r;
247  ps.mu = mu;
248  ps.ctx = Ctx;
249  #ifndef HAVE_STRUCTURED_EH
250  ok = PaintBitmap( &ps ); // Call back..
251  #else
252  __try { ok = PaintBitmap( &ps ); } // Call back..
254  {
255  TRACE( DP_ERROR, _F("Exception 0x%08X in user's PaintPitmap (%p).\n"),
256  GetExceptionCode(), PaintBitmap );
257  ok = false;
258  }
259  __end_except
260  #endif
261 
262  hbTmp = DeleteMemoryDC( hTmpDC, obmTmp ); // Retrieve the oversized bitmap.
263 
264  // Halftone stretch to target..
265 
266  if ( !ok ) DeleteBitmap( hbTmp ); // If painter returned false, or excepted..
267  else
268  {
269  HDC hMemDC = CreateMemoryDC( cx, cy, &obmMem ); // Create target w blank bitmap.
270  hTmpDC = CreateCompatibleDC( hMemDC ); // Create mem dc w/o bitmap.
271  obmTmp = SelectBitmap( hTmpDC, hbTmp ); // Select the oversized bitmap.
272 
273  SetStretchBltMode( hMemDC, HALFTONE );
274  SetBrushOrgEx( hMemDC, 0,0, NULL );
275  StretchBlt( hMemDC, 0,0, cx, cy, hTmpDC, 0,0, _cx, _cy, SRCCOPY );
276 
277  hBmp = DeleteMemoryDC( hMemDC, obmMem ); // Retrieve the antialiased bitmap.
278 
279  SelectBitmap( hTmpDC, obmTmp );
280  DeleteDC( hTmpDC );
281  }
282  }
283  //__cab_Exit:
284  return hBmp;
285 }
286 #pragma warning( default: 4533 )
287 
288 // DeleteObjectEx - Return NULL on success, else hObj.
289 
290 HGDIOBJ WINAPI DeleteObjectEx( HGDIOBJ hObj )
291 {
292  return hObj ? (DeleteObject( hObj ) ? NULL : hObj) : hObj;
293 }
294 
295 // Get the handle and optional data of a GDI object in HDC
296 
297 // x64 breakage: lbHatch may hold x64 HANDLE, making sizeof(LOGBRUSH) == sizeof(LOGPEN)
298 //void __checkGdiObjSizes()
299 //{
300 // DPrint( DP_DEBUG, _F("sizeof(LOGBRUSH) = %lu\n"), sizeof(LOGBRUSH) );
301 // DPrint( DP_DEBUG, _F("sizeof(LOGFONT) = %lu\n"), sizeof(LOGFONT) );
302 // DPrint( DP_DEBUG, _F("sizeof(LOGPEN) = %lu\n"), sizeof(LOGPEN) );
303 // DPrint( DP_DEBUG, _F("sizeof(EXTLOGPEN) = %lu\n"), sizeof(EXTLOGPEN) );
304 // DPrint( DP_DEBUG, _F("sizeof(BITMAP) = %lu\n"), sizeof(BITMAP) );
305 // DPrint( DP_DEBUG, _F("sizeof(DIBSECTION) = %lu\n"), sizeof(DIBSECTION) );
306 // DPrint( DP_DEBUG, _F("sizeof(WORD) = %lu\n"), sizeof(WORD) );
307 // DPrint( DP_DEBUG, _F("sizeof(LOGCOLORSPACE) = %lu\n"), sizeof(LOGCOLORSPACE) );
308 //}
309 
310 HGDIOBJ WINAPI GetCurrentObjectEx( HDC hdc, UINT ObjType, PVOID pObjData )
311 {
312  HGDIOBJ hObj = NULL;
313  UINT DataSize = 0;
314 
315  // DataSize used to be an argument, as in GetObject().
316  // As of x64, unfortunately LOGBRUSH.lbHatch may hold an x64 HANDLE,
317  // making sizeof(LOGBRUSH) == sizeof(LOGPEN), and thus defeating the
318  // original switch statement and forcing a breaking API change.
319 
320  if (pObjData)
321  switch( ObjType )
322  {
323  case OBJ_BRUSH: DataSize = sizeof(LOGBRUSH); break;
324  case OBJ_FONT: DataSize = sizeof(LOGFONT); break;
325  case OBJ_PEN: DataSize = sizeof(LOGPEN); break;
326  case OBJ_EXTPEN: DataSize = sizeof(EXTLOGPEN); break;
327  case OBJ_BITMAP: DataSize = sizeof(BITMAP); break;
328  case OBJ_PAL: DataSize = sizeof(WORD); break;
329  case OBJ_COLORSPACE: DataSize = sizeof(LOGCOLORSPACE); break;
330  case OBJ_DIBSECTION: // Special, unverified
331  DataSize = sizeof(DIBSECTION);
332  ObjType = OBJ_BITMAP;
333  break;
334  default: break;
335  }
336  hObj = GetCurrentObject( hdc, ObjType );
337  if (hObj && DataSize) GetObject( hObj, DataSize, pObjData ); // Get the object's data
338  return hObj;
339 }
340 
341 // Draw a bitmap through a monochrome mask
342 
343 bool WINAPI DrawMaskedBitmap( HDC hdc, int x, int y, HBITMAP hBmp, HBITMAP hMask )
344 {
345  BITMAP bm;
346  GetObject( hBmp, sizeof(bm), &bm );
347  HDC mdc = CreateCompatibleDC( hdc );
348  HBITMAP hbm = SelectBitmap( mdc, hBmp );
349 
350  bool ok = bool_cast( MaskBlt(
351  hdc, x,y, bm.bmWidth, bm.bmHeight, mdc,0,0, hMask,0,0, R4_MASKBLT
352  ));
353 
354  SelectBitmap( mdc, hbm );
355  DeleteDC( mdc );
356  return ok;
357 }
358 
359 // Draw a bitmap transparently
360 
362  HDC hdc, int x, int y, int w, int h, HBITMAP hBmp, COLORREF cTrans
363  )
364 {
365  BITMAP bm;
366  GetObject( hBmp, sizeof(bm), &bm );
367  if (!w) w = bm.bmWidth;
368  if (!h) h = bm.bmHeight;
369  HDC mdc = CreateCompatibleDC( hdc );
370  HBITMAP hbm = SelectBitmap( mdc, hBmp );
371 
372  bool ok = bool_cast( TransparentBlt(
373  hdc, x,y, w,h, mdc, 0,0, bm.bmWidth, bm.bmHeight, cTrans
374  ));
375 
376  SelectBitmap( mdc, hbm );
377  DeleteDC( mdc );
378  return ok;
379 }
380 
381 // Normal bitmap blits..
382 
383 void WINAPI DrawBitmap( HDC hdc, int x, int y, HBITMAP hBmp )
384 {
385  BITMAP bm;
386  GetObject( hBmp, sizeof(bm), &bm );
387  HDC mdc = CreateCompatibleDC( hdc );
388  HBITMAP hbm = SelectBitmap( mdc, hBmp );
389 
390  BitBlt( hdc, x, y, bm.bmWidth, bm.bmHeight, mdc, 0,0, SRCCOPY );
391 
392  SelectBitmap( mdc, hbm );
393  DeleteDC( mdc );
394 }
395 
396 // Stretched bitmap blit..
397 
398 void WINAPI DrawBitmapEx(
399  HDC hdc, int x, int y, int cx, int cy,
400  HBITMAP hBmp, int imx, int imy, int imw, int imh,
401  DWORD rasterOp
402  )
403 {
404  if (!imw || !imh)
405  {
406  BITMAP bm; GetObject( hBmp, sizeof(bm), &bm );
407  if (!imw) imw = bm.bmWidth;
408  if (!imh) imh = bm.bmHeight;
409  }
410  if (!cx || !cy)
411  {
412  HWND hWnd = WindowFromDC( hdc );
413  RECT r; GetClientRect( hWnd, &r );
414  if (!cx) cx = r.right;
415  if (!cy) cy = r.bottom;
416  }
417 
418  // PONDER: Constrain cx/cy and imw/imh to respective right/bottom corners?
419 
420  HDC mdc = CreateCompatibleDC( hdc );
421  HBITMAP hbm = SelectBitmap( mdc, hBmp );
422  int sbmode = SetStretchBltMode( hdc, HALFTONE );
423  SetBrushOrgEx( hdc, 0, 0, NULL );
424 
425  StretchBlt( hdc, x, y, cx, cy, mdc, imx, imy, imw, imh, rasterOp );
426 
427  SetStretchBltMode( hdc, sbmode );
428  SelectBitmap( mdc, hbm );
429  DeleteDC( mdc );
430 }
431 
432 // Draw a gradient filled rectangle
433 
434 #ifndef GRADIENT_D
435 void WINAPI DrawGradientRect( HDC hdc, PRECT pRc, COLORREF c1, COLORREF c2, UINT opt )
436 {
437  TRIVERTEX vtx[2];
438  GRADIENT_RECT mesh;
439 
440  SetTriVertex( &vtx[0], pr->left, pr->top, c1 );
441  SetTriVertex( &vtx[1], pr->right, pr->bottom, c2 );
442  SetRectMesh( &mesh, 0,1 );
443 
444  GradientFill( hdc, vtx,2, &mesh,1, opt );
445 }
446 #else
447 void WINAPI DrawGradientRect( HDC hdc, PRECT pRc, COLORREF c1, COLORREF c2, UINT type )
448 {
449  TRIVERTEX vtx[4];
450  if (type == GRADIENT_D) // Diagonal gradient :)
451  {
452  GRADIENT_TRIANGLE mesh[2];
453  COLORREF c3 = RGB(
454  BYTE( (WORD(GetRValue(c1)) + GetRValue(c2)) / 2),
455  BYTE( (WORD(GetGValue(c1)) + GetGValue(c2)) / 2),
456  BYTE( (WORD(GetBValue(c1)) + GetBValue(c2)) / 2)
457  );
458  // = GradientColor( c1,c2, 1,3 );
459  SetTriVertex( &vtx[0], pRc->left, pRc->bottom, c3 );
460  SetTriVertex( &vtx[1], pRc->left, pRc->top, c1 );
461  SetTriVertex( &vtx[2], pRc->right, pRc->top, c3 );
462  SetTriVertex( &vtx[3], pRc->right, pRc->bottom, c2 );
463  SetTriMesh( &mesh[0], 0, 1, 2 );
464  SetTriMesh( &mesh[1], 0, 2, 3 );
465  GradientFill( hdc, vtx,4, mesh,2, GRADIENT_FILL_TRIANGLE );
466  }
467  else // Horizontal or Vertical
468  {
469  GRADIENT_RECT mesh;
470  SetTriVertex( &vtx[0], pRc->left, pRc->top, c1 );
471  SetTriVertex( &vtx[1], pRc->right, pRc->bottom, c2 );
472  SetRectMesh( &mesh, 0,1 );
473  GradientFill( hdc, vtx,2, &mesh,1, type );
474  }
475 }
476 #endif
477 
478 void WINAPI SetTriVertex( PTRIVERTEX pVtx, int x, int y, COLORREF cr, BYTE Alpha )
479 {
480  pVtx->x = x; pVtx->y = y;
481  pVtx->Red = COLOR16( GetRValue( cr )) << 8;
482  pVtx->Green = COLOR16( GetGValue( cr )) << 8;
483  pVtx->Blue = COLOR16( GetBValue( cr )) << 8;
484  pVtx->Alpha = COLOR16( Alpha ) << 8;
485 }
486 
487 void WINAPI SetTriMesh( PGRADIENT_TRIANGLE pTri, UINT Vtx1, UINT Vtx2, UINT Vtx3 )
488 {
489  pTri->Vertex1 = Vtx1;
490  pTri->Vertex2 = Vtx2;
491  pTri->Vertex3 = Vtx3;
492 }
493 
494 void WINAPI SetRectMesh( PGRADIENT_RECT pRect, UINT TopLeft, UINT BotRight )
495 {
496  pRect->UpperLeft = TopLeft;
497  pRect->LowerRight = BotRight;
498 }
499 
500 void WINAPI SetRedraw( HWND hwnd, bool on )
501 {
502  WM_SetRedraw( hwnd, on );
503  if (on) InvalidateRect( hwnd, NULL, false );
504 }
505 
506 void WINAPI Line( HDC hdc, int x1, int y1, int x2, int y2 )
507 {
508  MoveToEx( hdc, x1, y1, NULL );
509  LineTo( hdc, x2, y2 );
510 }
511 
513  POINT* Vtx, int xOrg, int yOrg, int Radius, double Orientation )
514 {
515  static const double angleStep = (2.0 * M_PI) / 3.0;
516  double& dir = Orientation; // Fingersaving alias..
517 
518  // PONDER: Eliminate one sin/cos pair call by precomputing sin/cos pairs
519  // for Orientation and angleStep and using those for the Vtx calculations.
520 
521  Vtx[0].x = xOrg + int( Radius * cos( dir ));
522  Vtx[0].y = yOrg - int( Radius * sin( dir ));
523  Vtx[1].x = xOrg + int( Radius * cos( dir + angleStep ));
524  Vtx[1].y = yOrg - int( Radius * sin( dir + angleStep ));
525  Vtx[2].x = xOrg + int( Radius * cos( dir - angleStep ));
526  Vtx[2].y = yOrg - int( Radius * sin( dir - angleStep ));
527 }
528 
529 void WINAPI DrawIsoTriangle(
530  HDC hdc, int xOrg, int yOrg, int Radius, double Orientation )
531 {
532  POINT pt[3];
533  /*
534  Usage example:
535  HBRUSH hbr = SelectBrush( hdc, GetStockBrush( HOLLOW_BRUSH ));
536  HPEN hpen = SelectPen( hdc, GetStockPen( WHITE_PEN ));
537  int x = rDisp.left + (rDisp.right - rDisp.left) / 2;
538  int y = rDisp.top + (rDisp.bottom - rDisp.top) / 2;
539  DrawIsoTriangle( hdc, x, y, 100, -M_PI/2.0 );
540  SelectPen( hdc, hpen );
541  SelectBrush( hdc, hbr );
542  */
543  GetIsoTriangleVertices( pt, xOrg, yOrg, Radius, Orientation );
544  Polygon( hdc, pt, 3 );
545  //IF_DEBUG( Line( hdc, xOrg, yOrg, pt[0].x, pt[0].y ));
546 }
547 
548 // Color scaling
549 
550 static BYTE _mulimClr( BYTE val, BYTE mul, BYTE div )
551 {
552  WORD lum = WORD( val ) * mul / div;
553  return (lum > 255) ? 255 : (BYTE) lum;
554 }
555 
556 #if !USE_SCALECOLOR_ASM // In _gradcolor.asm
557 // FIXME: The assembly implementation needs rethinking...
558 COLORREF WINAPI ScaleColorRef( COLORREF color, BYTE mul, BYTE div )
559 {
560  COLORREF result;
561  if (mul == div) result = color;
562  else
563  {
564  BYTE rr = _mulimClr( GetRValue( color ), mul, div );
565  BYTE gg = _mulimClr( GetGValue( color ), mul, div );
566  BYTE bb = _mulimClr( GetBValue( color ), mul, div );
567  result = RGB( rr,gg,bb );
568  }
569  return result;
570 }
571 #endif
572 
573 #if !USE_GRADIENTCOLOR_ASM // C++ fallback implementation
574 //
575 // GradientColor procuces a smooth color crossfade from c1 to c2.
576 // Length is the desired run length from c1 to c2, and Ix is the step nr.
577 //
578 COLORREF WINAPI GradientColor( COLORREF c1, COLORREF c2, WORD Ix, WORD Length )
579 {
580  BYTE r1 = GetRValue( c1 );
581  BYTE g1 = GetGValue( c1 );
582  BYTE b1 = GetBValue( c1 );
583  SHORT dr = SHORT(GetRValue( c2 )) - r1;
584  SHORT dg = SHORT(GetGValue( c2 )) - g1;
585  SHORT db = SHORT(GetBValue( c2 )) - b1;
586  WORD N = Length-1; // Divisor need to comply with Ix 0..Length-1
587  WORD r = WORD(r1) + ((dr * SHORT(Ix)) / N);
588  WORD g = WORD(g1) + ((dg * SHORT(Ix)) / N);
589  WORD b = WORD(b1) + ((db * SHORT(Ix)) / N);
590  return RGB( BYTE(r), BYTE(g), BYTE(b) );
591 }
592 #endif
593 
594 // Convert RGB to weighted grayscale.
595 
596 COLORREF WINAPI GrayScaleColor( COLORREF rgb )
597 {
598  static const float coef[3] = { 0.2126f, 0.7152f, 0.0722f }; // sRGB
599  //static const float coef[3] = { 0.2989f, 0.5870f, 0.1140f }; // CCIR 601 (NTSC)
600  BYTE luma = BYTE(
601  coef[0] * GetRValue(rgb) +
602  coef[1] * GetGValue(rgb) +
603  coef[2] * GetBValue(rgb)
604  );
605  return RGB( luma,luma,luma );
606 }
607 
608 // Region supplements
609 
610 int WINAPI MapRegionToWindow( HRGN hRgn, HWND hWnd )
611 {
612  POINT pt = {0,0};
613  MapWindowPoints( HWND_DESKTOP, hWnd, &pt, 1 );
614  return OffsetRgn( hRgn, pt.x, pt.y );
615 }
616 
617 RGNDATA* WINAPI AllocAndGetRegionData( HRGN hRgn, RECT** ppRc )
618 {
619  DWORD cbRgn = GetRegionData( hRgn, 0, NULL );
620  RGNDATA* pRgn = (RGNDATA*) mem_Alloc( cbRgn );
621  if (pRgn)
622  {
623  GetRegionData( hRgn, cbRgn, pRgn );
624  if (ppRc) *ppRc = (RECT*) pRgn->Buffer;
625  }
626  return pRgn;
627 }
628 
629 RGNDATA* WINAPI FreeRegionData( RGNDATA* pRgn )
630 {
631  return (RGNDATA*) mem_Free( pRgn ); // Null-safe
632 }
633 
634 #if _DEBUG // Dump region data to the debugger.
635 void WINAPI DumpRegionData( CSTR Title, HRGN hRgn )
636 {
637  RECT* pr = NULL;
638  RGNDATA* pRgn = AllocAndGetRegionData( hRgn, &pr );
639  if (pRgn)
640  {
641  RECT r = pRgn->rdh.rcBound;
642  DPrint( DP_INFO, _F("%s: Bounds={%li,%li,%li,%li}, Count=%lu, Type=%lu\n"),
643  Title, r.left, r.top, r.right, r.bottom, pRgn->rdh.nCount, pRgn->rdh.iType
644  );
645  for( DWORD ix = 0, N = pRgn->rdh.nCount; ix < N; ++ix )
646  {
647  r = *pr++;
648  DPrint( DP_INFO, _F(" Rect[%lu] = {%li,%li,%li,%li}\n"),
649  ix, r.left, r.top, r.right, r.bottom );
650  }
651  pRgn = FreeRegionData( pRgn );
652  }
653 }
654 #endif
655 
656 // Path/Region supplements
657 
658 // Retrieve the current path data from a display context.
659 
660 bool WINAPI GetGdiPathData( HDC hdc, OUT PGdiPathData pData )
661 {
662  int nPts = GetPath( hdc, NULL, NULL, 0 );
663  bool ok = (nPts > 1);
664  TRACE_IF( !ok, DP_ERROR, _F("GetPath == %i: %s\n"), nPts, SysErrorMsg() );
665  // GetPath sometimes fails (with no error code) even when there is a valid path.
666  // I.e: GetPath( hdc, 0,0,0 ) == -1, and GetLastError() == 0.
667  // It seems to be a somewhat stochastic GDI bug..?
668  // Converting the path to a region appears more reliable.
669  if (ok)
670  {
671  LPPOINT pPt = (LPPOINT) mem_Alloc( nPts * sizeof(POINT) + nPts );
672  LPBYTE pType = (LPBYTE)( pPt + nPts ); // NB: C pointer arithmetic.
673  if ( ok = (pPt != NULL) )
674  {
675  int cPts = GetPath( hdc, pPt, pType, nPts );
676  ok = (cPts == nPts);
677  if (ok)
678  {
679  RECT r = { LONG_MAX, LONG_MAX, 0,0 }; // bounds
680  LPPOINT ppt = pPt;
681  for( int ix = 0; ix < cPts; ix++, ppt++ )
682  {
683  long x = ppt->x, y = ppt->y; // pre-ref to quicken access
684  if (x < r.left) r.left = x;
685  if (x > r.right) r.right = x;
686  if (y < r.top) r.top = y;
687  if (y > r.bottom) r.bottom = y;
688  }
689  pData->Bounds = r;
690  pData->nPoints = cPts;
691  pData->pPoint = pPt;
692  pData->pType = pType;
693  }
694  else
695  {
696  DWORD err = GetLastError(); // Pray GetPath actually used SetLastError()
697  mem_Free( pPt ); // Dispose the buffer so we don't leak.
698  SetLastError( err );
699  }
700  }
701  }
702  return ok;
703 }
704 
705 // Dispose path data retrieved by GetGdiPathData().
706 
707 void WINAPI FreeGdiPathData( PGdiPathData pData )
708 {
709  mem_Free( pData->pPoint ); // Null-safe
710 }
711 
712 // Compute the bounding rect for the current HDC path.
713 
714 bool WINAPI GetGdiPathBounds( HDC hdc, PRECT pBounds )
715 {
716  GdiPathData pd;
717  bool ok = GetGdiPathData( hdc, &pd );
718  if (ok)
719  {
720  *pBounds = pd.Bounds;
721  FreeGdiPathData( &pd );
722  }
723  return ok;
724 }
725 
726 // Convert the current HDC path to a region and retrieve the region data.
727 
728 HRGN WINAPI GetGdiPathRgn( HDC hdc, OUT RGNDATA** pRgnData, OPTOUT RECT** pRgnRects )
729 {
730  HRGN pathRgn = PathToRegion( hdc );
731  TRACE_IF( !pathRgn, DP_ERROR, _F("PathToRegion: %s\n"), SysErrorMsg() );
732  if (pathRgn)
733  {
734  *pRgnData = AllocAndGetRegionData( pathRgn, pRgnRects );
735  }
736  return pathRgn;
737 }
738 
739 // Convert a HDC path into a region and get it's bounding rect.
740 // Somewhat superfluous as you may use PathToRegion and GetRgnBox
741 // if that's all you need. Retained just for edification..
742 
743 HRGN WINAPI GetGdiPathRgnBounds( HDC hdc, OUT PRECT pBounds )
744 {
745  RGNDATA* rgnData;
746  RECT* rgnRects; // Region rectangles.
747  HRGN pathRgn = GetGdiPathRgn( hdc, &rgnData, &rgnRects );
748  if (pathRgn)
749  {
750  *pBounds = rgnData->rdh.rcBound;
751  FreeRegionData( rgnData );
752  }
753  return pathRgn;
754 }
755 
756 // Offset an array of points by dx/dy.
757 
758 void OffsetPoints( POINT* Pts, UINT nPts, int dx, int dy )
759 {
760  POINT* pt = Pts;
761  for( UINT ix=0; ix < nPts; ix++, pt++ )
762  {
763  pt->x += dx;
764  pt->y += dy;
765  }
766 }
767 
768 // Offset the retrieved region data by dx/dy.
769 
770 void OffsetRgnData( PRGNDATA prd, int dx, int dy )
771 {
772  PRECT pr = (PRECT) prd->Buffer;
773  OffsetRect( &prd->rdh.rcBound, dx, dy );
774  for( DWORD ix=0, N=prd->rdh.nCount; ix < N; ix++, pr++ )
775  {
776  OffsetRect( pr, dx, dy );
777  }
778 }
779 
780 // An initialized MAT2 is a mandatory parameter for GetGlyphOutline().
781 
782 void SetIdentityMat2( MAT2* pm )
783 {
784  static const FIXED zero = {0,0}, one = {0,1};
785  pm->eM11 = pm->eM22 = one;
786  pm->eM12 = pm->eM21 = zero;
787 }
788 
789 // EOF
unsigned long DWORD
Definition: Common.h:414
#define OBJ_DIBSECTION
Definition: UtilFunc.h:1941
void SetIdentityMat2(MAT2 *pm)
Definition: GdiUtil.cpp:782
void WINAPI SetTriMesh(PGRADIENT_TRIANGLE pTri, UINT Vtx1, UINT Vtx2, UINT Vtx3)
Definition: GdiUtil.cpp:487
void WINAPI ReleaseDesktopDC(HDC hDeskDC)
Definition: GdiUtil.cpp:102
#define SYSMET(Id)
Definition: UtilFunc.h:923
#define CSTR
Definition: Common.h:329
void WINAPI FreeGdiPathData(PGdiPathData pData)
Definition: GdiUtil.cpp:707
HGDIOBJ WINAPI GetCurrentObjectEx(HDC hdc, UINT ObjType, PVOID pObjData)
Definition: GdiUtil.cpp:310
HGDIOBJ WINAPI DeleteObjectEx(HGDIOBJ hObj)
Definition: GdiUtil.cpp:290
unsigned short WORD
Definition: Common.h:413
PVOID ctx
User's context, if any.
Definition: UtilFunc.h:2004
HDC WINAPI GetDesktopDC()
Definition: GdiUtil.cpp:97
HDC WINAPI ReleaseWndDC(HDC dc)
Definition: GdiUtil.cpp:88
RECT MkRect(LONG L, LONG T, LONG R, LONG B)
Definition: UtilFunc.cpp:46
int WINAPI ScreenFontHeight(WORD Points)
Definition: GdiUtil.cpp:52
HFONT WINAPI CreateFontEx(CSTR Typeface, int Points, int Weight, DWORD Charset, DWORD Quality)
Definition: GdiUtil.cpp:30
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
void WINAPI DrawBitmapEx(HDC hdc, int x, int y, int cx, int cy, HBITMAP hBmp, int imx, int imy, int imw, int imh, DWORD rasterOp)
Definition: GdiUtil.cpp:398
#define GetCurrentFontEx(dc, plfont)
Definition: UtilFunc.h:1943
bool WINAPI GetGdiPathBounds(HDC hdc, PRECT pBounds)
Definition: GdiUtil.cpp:714
bool WINAPI DrawTransparentBitmap(HDC hdc, int x, int y, int w, int h, HBITMAP hBmp, COLORREF cTrans)
Definition: GdiUtil.cpp:361
#define OPTOUT
Definition: Common.h:264
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
void WINAPI SetRedraw(HWND hwnd, bool on)
Definition: GdiUtil.cpp:500
#define TRACE(_lvl,...)
Definition: Debug.h:216
#define GRADIENT_D
Definition: UtilFunc.h:2099
void OffsetPoints(POINT *Pts, UINT nPts, int dx, int dy)
Definition: GdiUtil.cpp:758
void OffsetRgnData(PRGNDATA prd, int dx, int dy)
Definition: GdiUtil.cpp:770
void WINAPI SetTriVertex(PTRIVERTEX pVtx, int x, int y, COLORREF cr, BYTE Alpha)
Definition: GdiUtil.cpp:478
int WINAPI MapRegionToWindow(HRGN hRgn, HWND hWnd)
Definition: GdiUtil.cpp:610
#define __except_execute
Definition: Common.h:647
#define WM_SetRedraw(hwnd, on)
Definition: UtilFunc.h:1132
UINT mu
Scaling multiplier.
Definition: UtilFunc.h:2003
COLORREF WINAPI ScaleColorRef(COLORREF color, BYTE mul, BYTE div)
Definition: GdiUtil.cpp:558
void WINAPI DrawGradientRect(HDC hdc, PRECT pRc, COLORREF c1, COLORREF c2, UINT opt)
Definition: GdiUtil.cpp:435
RGNDATA *WINAPI FreeRegionData(RGNDATA *pRgn)
Definition: GdiUtil.cpp:629
#define TRACE_IF(cond,...)
Definition: Debug.h:227
void WINAPI SetRectMesh(PGRADIENT_RECT pRect, UINT TopLeft, UINT BotRight)
Definition: GdiUtil.cpp:494
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
void WINAPI GetScreenLPI(PPOINT pLpi)
Definition: GdiUtil.cpp:141
COLORREF WINAPI GradientColor(COLORREF c1, COLORREF c2, WORD Ix, WORD Length)
HBITMAP WINAPI CreateMaskBitmap(HBITMAP img, COLORREF transp)
Definition: GdiUtil.cpp:193
RGNDATA *WINAPI AllocAndGetRegionData(HRGN hRgn, RECT **ppRc)
Definition: GdiUtil.cpp:617
bool(__stdcall * PFnPaintBitmap)(PAINTBMPSTRUCT *p)
Definition: UtilFunc.h:2010
CSTR SysErrorMsg(DWORD Err=0, TSTR Buf=NULL, UINT Length=0)
Definition: Debug.cpp:39
void WINAPI DrawBitmap(HDC hdc, int x, int y, HBITMAP hBmp)
Definition: GdiUtil.cpp:383
HRGN WINAPI GetGdiPathRgnBounds(HDC hdc, OUT PRECT pBounds)
Definition: GdiUtil.cpp:743
#define SYSHBR(id)
Definition: UtilFunc.h:1726
struct _gdiPathData * PGdiPathData
void WINAPI Line(HDC hdc, int x1, int y1, int x2, int y2)
Definition: GdiUtil.cpp:506
bool __forceinline bool_cast(BOOL B52)
Definition: Common.h:767
#define DP_ERROR
Definition: Debug.h:82
bool WINAPI GetGdiPathData(HDC hdc, OUT PGdiPathData pData)
Definition: GdiUtil.cpp:660
HRGN WINAPI GetGdiPathRgn(HDC hdc, OUT RGNDATA **pRgnData, OPTOUT RECT **pRgnRects)
Definition: GdiUtil.cpp:728
HDC WINAPI CreateMemoryDC(UINT cx, UINT cy, HBITMAP *pOldBmp)
Definition: GdiUtil.cpp:109
Debug and error handling support.
RECT rcPaint
Upscaled drawing rect.
Definition: UtilFunc.h:2002
Common include; Added types, small "ubiquitous" utilities, et c.
void WINAPI GetIsoTriangleVertices(POINT *Vtx, int xOrg, int yOrg, int Radius, double Orientation)
Definition: GdiUtil.cpp:512
POINT WINAPI WhereXY(HDC dc)
Definition: GdiUtil.cpp:78
COLORREF WINAPI GrayScaleColor(COLORREF rgb)
Definition: GdiUtil.cpp:596
#define _F(s)
Definition: Debug.h:49
HBITMAP WINAPI DeleteMemoryDC(HDC hMemDC, HBITMAP oldBmp)
Definition: GdiUtil.cpp:126
HBITMAP WINAPI CreateIconBitmap(HICON hIcon, HBRUSH hbrBkg, UINT cx, UINT cy)
Definition: GdiUtil.cpp:153
#define DP_INFO
Definition: Debug.h:84
HDC hDC
DC to paint on.
Definition: UtilFunc.h:2001
int WINAPI FontHeight(HDC hdc, int Points)
Definition: GdiUtil.cpp:43
#define R4_MASKBLT
Definition: TernaryOp.h:46
bool WINAPI DrawMaskedBitmap(HDC hdc, int x, int y, HBITMAP hBmp, HBITMAP hMask)
Definition: GdiUtil.cpp:343
void WINAPI DrawIsoTriangle(HDC hdc, int xOrg, int yOrg, int Radius, double Orientation)
Definition: GdiUtil.cpp:529
HBITMAP WINAPI CreateAntialiasedBitmap(UINT cx, UINT cy, UINT mu, PFnPaintBitmap PaintBitmap, PVOID Ctx)
Definition: GdiUtil.cpp:222
#define DP_WARNING
Definition: Debug.h:83
unsigned char BYTE
Definition: Common.h:412
RECT Bounds
Bounding rect for the whole path.
Definition: UtilFunc.h:2135
void WINAPI DumpRegionData(CSTR Title, HRGN hRgn)
Definition: GdiUtil.cpp:635
HFONT WINAPI GetWndFont(HWND hWnd, LOGFONT *pLogFont)
Definition: GdiUtil.cpp:66