ecere/gfx: Font outline support
[sdk] / ecere / src / gfx / drivers / Win32PrinterDisplayDriver.ec
1 namespace gfx::drivers;
2
3 import "instance"
4
5 #if defined(__WIN32__)
6
7 #undef _WIN32_WINNT
8 #define _WIN32_WINNT 0x0502
9 #define WIN32_LEAN_AND_MEAN
10 #define UNICODE
11 #define Method _Method
12 #define String _String
13 #define strlen _strlen
14 #include <windows.h>
15 #include <winspool.h>
16 #undef Method
17 #undef String
18 #undef strlen
19
20 default wchar_t *wcstok(wchar_t *strToken,const wchar_t *strDelimit);
21
22 import "Display"
23
24 //static char szMessage[]= L"Printing ECERE Document...";
25 static char szMessage[]= "Printing ECERE Document...";
26
27 /*
28 static define RESX = 850;
29 static define RESY = 1100;
30 */
31
32 class Win32PrinterDisplay : struct
33 {
34    HPALETTE palette;
35    LOGPALETTE * logPalette;
36    Point offset;
37    int width, height;
38    bool completed;
39
40    HDC hdc;
41    HRGN rgn;
42    RGNDATA * data;
43
44    ~Win32PrinterDisplay()
45    {
46       //if(memDC) DeleteDC(memDC);
47       //if(memBitmap) DeleteObject(memBitmap);
48       if(palette) DeleteObject(palette);
49       delete logPalette;
50    }
51 };
52 /*
53 static byte defaultRGBLookup[32768];
54 static bool rgbLookupSet = false;
55 */
56 class Win32PrinterSystem : struct
57 {
58    HDC hdc;
59    HDC tmpDC, bmpDC;
60    int depth;
61    int resX, resY;   // Save the display here, support only one display at a time
62
63    ~Win32PrinterSystem()
64    {
65
66    }
67 };
68
69 class Win32PrinterSurface : struct
70 {
71    HDC hdc;
72    HRGN rgn, clippedRgn;
73    COLORREF color, backColor;
74
75    Point offset;
76    Box box, unclippedBox;
77 };
78
79 class Win32PrinterBitmap : struct
80 {
81    HBITMAP bmp, mask;
82    HDC memDC;
83 };
84
85 static PixelFormat GetColorFormat(int depth)
86 {
87    if(depth == 8)
88       return pixelFormat8;
89    else if(depth == 16)
90       return pixelFormat555;
91    else
92       return pixelFormat888;
93 }
94
95 static define dpi = 100;
96 static define inchToMillimeter = 0.039370;
97 class Win32PrinterDisplayDriver : DisplayDriver
98 {
99    class_property(name) = "Win32Printer";
100    class_property(printer) = bool::true;
101
102    bool CreateDisplaySystem(DisplaySystem displaySystem)
103    {
104       displaySystem.driverData = Win32PrinterSystem { };
105       return true; //false;
106    }
107
108    void DestroyDisplaySystem(DisplaySystem displaySystem)
109    {
110       Win32PrinterSystem gdiSystem = displaySystem.driverData;
111       DeleteDC(gdiSystem.tmpDC);
112       DeleteDC(gdiSystem.bmpDC);
113       DeleteDC(gdiSystem.hdc);
114       displaySystem.driverData = null;
115       delete gdiSystem;
116    }
117
118    void DestroyDisplay(Display display)
119    {
120       Win32PrinterSystem gdiSystem = display.displaySystem.driverData;
121       Win32PrinterDisplay gdiDisplay = display.driverData;
122       if(gdiDisplay)
123       {
124                 EndPage(gdiDisplay.hdc);
125          Escape(gdiDisplay.hdc, ENDDOC, 0, null, null);
126       }
127
128       // ((subclass(DisplayDriver))class(LFBDisplayDriver)).DestroyDisplay(display);
129       delete gdiDisplay;
130       display.driverData = null;
131
132       if(gdiSystem)
133       {
134          DeleteDC(gdiSystem.tmpDC);
135          DeleteDC(gdiSystem.bmpDC);
136          DeleteDC(gdiSystem.hdc);
137       }
138    }
139
140    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
141    {
142       Win32PrinterDisplay gdiDisplay = display.driverData;
143       if(display.displaySystem.pixelFormat == pixelFormat8)
144       {
145          int c;
146          ColorAlpha realPalette[256];
147          int reserved = (display.flags.fullScreen) ? 1 : 10;
148          HDC hdc = gdiDisplay.hdc;
149          if(hdc)
150          {
151             //if(reserved > 1)
152             {
153                GetSystemPaletteEntries(hdc,0,256,(PALETTEENTRY *)realPalette);
154                for(c = 0; c<256; c++)
155                   realPalette[c] = RGB(realPalette[c].color.r, realPalette[c].color.g, realPalette[c].color.b);
156
157                // *** Reserved Palette Handling ***
158                /*if(!palette)
159                {
160                   palette = GetDefaultPalette();
161                   CopyBytesBy4(realPalette+reserved,palette+reserved,256-2*reserved);
162                   if(!rgbLookupSet)
163                      for(c = 0; c<32768; c++)
164                         defaultRGBLookup[c] = (byte)BestColorMatch(realPalette, 1,255, (Color555)c);
165                   rgbLookupSet = true;
166                   CopyBytes(gdiDisplay.rgbLookup, defaultRGBLookup, 32768);
167                   for(c=0; c<256; c++)
168                   {
169                      int i;
170                      for(i=0; i<LIGHTSTEPS; i++)
171                      {
172                         gdiDisplay.lightTable[c][i]=gdiDisplay.rgbLookup[(uint16)Color555 {
173                                 (byte)(((uint16)realPalette[c].color.r*i) >> LIGHTSHIFT),
174                                 (byte)(((uint16)realPalette[c].color.g*i) >> LIGHTSHIFT),
175                                 (byte)(((uint16)realPalette[c].color.b*i) >> LIGHTSHIFT) }];
176                      }
177                   }
178                   CopyBytesBy4(gdiDisplay.bitmap.palette, realPalette, 256);
179                }
180                else
181                */
182                {
183                   CopyBytesBy4(realPalette+reserved,palette+reserved,256-2*reserved);
184                   // ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetPalette(display, realPalette, colorMatch);
185                }
186             }
187             /*else
188                ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetPalette(display, palette, colorMatch);*/
189             // *********************************
190
191             gdiDisplay.logPalette->palVersion = 0x300;
192             gdiDisplay.logPalette->palNumEntries = 256;
193
194             for(c = 0; c < 256; c++)
195             {
196                gdiDisplay.logPalette->palPalEntry[c].peFlags = PC_NOCOLLAPSE;
197                gdiDisplay.logPalette->palPalEntry[c].peRed   = realPalette[c].color.r;
198                gdiDisplay.logPalette->palPalEntry[c].peGreen = realPalette[c].color.g;
199                gdiDisplay.logPalette->palPalEntry[c].peBlue  = realPalette[c].color.b;
200             }
201
202             if(!gdiDisplay.palette)
203                gdiDisplay.palette = CreatePalette(gdiDisplay.logPalette);
204             else
205                SetPaletteEntries(gdiDisplay.palette, 0, 256, gdiDisplay.logPalette->palPalEntry);
206
207             SelectPalette(hdc, gdiDisplay.palette, FALSE);
208             RealizePalette(hdc);
209
210             // SetDIBColorTable(gdiDisplay.hdc, 0, 256, (RGBQUAD *)gdiDisplay.bitmap.palette);
211          }
212       }
213    }
214
215    bool CreateDisplay(Display display)
216    {
217       bool result = false;
218
219       if(display)
220       {
221          Win32PrinterDisplay gdiDisplay = display.driverData = Win32PrinterDisplay { };
222          if((gdiDisplay.logPalette = (LOGPALETTE *)new0 byte[sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*256]) /*&&
223             ((subclass(DisplayDriver))class(LFBDisplayDriver)).CreateDisplay(display)*/)
224          {
225             result = true;
226          }
227       }
228       return result;
229    }
230
231    bool DisplaySize(Display display, int width, int height)
232    {
233       Win32PrinterSystem gdiSystem = display.displaySystem.driverData;
234       Win32PrinterDisplay gdiDisplay = display.driverData;
235       bool result = false;
236       HDC hdc = gdiSystem.hdc;
237
238       if(!width || !height)
239          result = true;
240       else
241       {
242          if(!hdc)
243          {
244                 uint16 szPrinter[160];
245                 uint16 *szDevice, *szDriver, *szOutput;
246
247             GetProfileString(L"windows", L"device", L"...", szPrinter, 160);
248                 szDevice = wcstok(szPrinter, L",");
249                 szDriver = wcstok(null,      L",");
250                 szOutput = wcstok(null,      L",");
251             if(szDevice && szDriver && szOutput)
252             {
253                DEVMODE * devMode = null;
254                HANDLE hPrinter = null;
255                uint size;
256                OpenPrinter(szPrinter, &hPrinter, null);
257                size = DocumentProperties(null, hPrinter, szDevice, null, null, 0);
258                devMode = (DEVMODE *)new0 byte[size];
259                DocumentProperties(null, hPrinter, szDevice, devMode, null, DM_OUT_BUFFER);
260                devMode->dmFields |= DM_ORIENTATION | DM_PAPERSIZE;
261                devMode->dmOrientation = (width > height) ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
262                if(height == (int)(8.5*dpi) && width == 11*dpi)
263                   devMode->dmPaperSize = DMPAPER_LETTER;
264                else if(height == (int)(8.5*dpi) && width == 14*dpi)
265                   devMode->dmPaperSize = DMPAPER_LEGAL;
266                else if(height == 11*dpi && width == 17*dpi)
267                   devMode->dmPaperSize = DMPAPER_11X17;
268                else
269                {
270                   short w = (short)((double)width * 10 / dpi / inchToMillimeter);
271                   short h = (short)((double)height * 10 / dpi / inchToMillimeter);
272                   devMode->dmPaperSize = DMPAPER_USER;
273                   devMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
274                   devMode->dmPaperLength = w > h ? w : h;
275                   devMode->dmPaperWidth = w < h ? w : h;
276                }
277                DocumentProperties(null, hPrinter, szDevice, devMode, devMode, DM_IN_BUFFER|DM_OUT_BUFFER);
278                gdiSystem.hdc = CreateDC(szDriver, szDevice, szOutput, devMode);
279                delete devMode;
280                ClosePrinter(hPrinter);
281                if(gdiSystem.hdc)
282                {
283                   gdiSystem.tmpDC = CreateCompatibleDC(gdiSystem.hdc);
284                   gdiSystem.bmpDC = CreateCompatibleDC(gdiSystem.hdc);
285                   gdiSystem.depth = GetDeviceCaps(gdiSystem.hdc, BITSPIXEL);
286                   gdiSystem.depth = 32;
287                   display.displaySystem.pixelFormat = GetColorFormat(gdiSystem.depth);
288
289                   /*
290                   SetMapMode(gdiSystem.hdc, MM_ANISOTROPIC);
291                   SetWindowExtEx(gdiSystem.hdc, RESX, RESY, null);
292                   SetViewportExtEx(gdiSystem.hdc, GetDeviceCaps(gdiSystem.hdc, HORZRES), GetDeviceCaps(gdiSystem.hdc, VERTRES), null);
293                   */
294                   SetMapMode(gdiSystem.hdc, MM_TEXT);
295
296                   {
297                      const String docName = printingDocumentName ? printingDocumentName : szMessage;
298                      char curDir[MAX_LOCATION];
299                      GetWorkingDir(curDir, MAX_LOCATION);
300
301                      if(Escape(gdiSystem.hdc, STARTDOC, strlen(docName), docName, null ) > 0)
302                         {
303                                 StartPage(gdiSystem.hdc);
304                         result = true;
305                      }
306                      ChangeWorkingDir(curDir);
307                   }
308                }
309                //displaySystem.flags.memBackBuffer = true;
310             }
311          }
312          hdc = gdiSystem.hdc;
313          gdiDisplay.hdc = gdiSystem.hdc;
314         gdiDisplay.width = GetDeviceCaps(hdc, HORZRES);
315         gdiDisplay.height = GetDeviceCaps(hdc, VERTRES);
316
317          gdiSystem.resX = display.width = width;
318          gdiSystem.resY = display.height = height;
319
320          SelectObject(gdiDisplay.hdc,GetStockObject(DC_PEN));
321          SelectObject(gdiDisplay.hdc,GetStockObject(DC_BRUSH));
322          SetBkMode(gdiDisplay.hdc, TRANSPARENT);
323          result = true;
324       }
325       return result;
326    }
327
328    void DisplayPosition(Display display, int x, int y)
329    {
330       Win32PrinterDisplay gdiDisplay = display.driverData;
331       gdiDisplay.offset.x = x;
332       gdiDisplay.offset.y = y;
333
334    }
335
336    void RestorePalette(Display display)
337    {
338       Win32PrinterDisplay gdiDisplay = display.driverData;
339       HDC hdc = gdiDisplay.hdc;
340       if(hdc)
341       {
342          if(gdiDisplay.palette)
343          {
344             SelectPalette(hdc, gdiDisplay.palette, FALSE);
345             RealizePalette(hdc);
346          }
347       }
348    }
349
350    #define MAX_EXPOSED  50
351
352    void StartUpdate(Display display)
353    {
354       Win32PrinterDisplay gdiDisplay = display.driverData;
355       if(gdiDisplay && !gdiDisplay.completed)
356       {
357          GdiSetBatchLimit(1000);
358
359          gdiDisplay.rgn = CreateRectRgn(0,0,0,0);
360          gdiDisplay.data = (RGNDATA *) new0 byte[sizeof(RGNDATAHEADER) + sizeof(RECT) * MAX_EXPOSED];
361          if(gdiDisplay.palette)
362             SelectPalette(gdiDisplay.hdc, gdiDisplay.palette, FALSE);
363       }
364    }
365
366    void Scroll(Display display, Box scroll, int x, int y, Extent dirty)
367    {
368
369    }
370
371    void Update(Display display, Box updateBox)
372    {
373
374    }
375
376    void EndUpdate(Display display)
377    {
378       Win32PrinterDisplay gdiDisplay = display.driverData;
379       if(gdiDisplay && !gdiDisplay.completed)
380       {
381          DeleteObject(gdiDisplay.rgn);
382          delete gdiDisplay.data;
383          gdiDisplay.data = null;
384          gdiDisplay.completed = true;
385       }
386    }
387
388    void NextPage(Display display)
389    {
390       Win32PrinterDisplay gdiDisplay = display.driverData;
391       gdiDisplay.completed = false;
392       EndPage(gdiDisplay.hdc);
393       StartPage(gdiDisplay.hdc);
394    }
395
396    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
397    {
398       // (((subclass(DisplayDriver))class(LFBDisplayDriver)).FreeBitmap(displaySystem, bitmap);
399       Win32PrinterBitmap gdiBitmap = bitmap.driverData;
400
401       if(gdiBitmap.memDC)
402          DeleteDC(gdiBitmap.memDC);
403       if(gdiBitmap.mask)
404          DeleteObject(gdiBitmap.mask);
405       if(gdiBitmap.bmp)
406          DeleteObject(gdiBitmap.bmp);
407       delete (Win32PrinterBitmap)gdiBitmap;
408       bitmap.driverData = null;
409       bitmap.driver = null;
410    }
411
412    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
413    {
414       // return (((subclass(DisplayDriver))class(LFBDisplayDriver)).MakeDDBitmap(displaySystem, bitmap, mipMaps);
415
416       if(bitmap.Convert(null, pixelFormat888, null))
417       {
418          Win32PrinterSystem gdiSystem = displaySystem.driverData;
419          Win32PrinterBitmap gdiBitmap = bitmap.driverData = Win32PrinterBitmap { };
420          BITMAPINFO * info = new0 BITMAPINFO[1];
421          if(!info) return false;
422
423          info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
424          info->bmiHeader.biPlanes = 1;
425          info->bmiHeader.biWidth = bitmap.width;
426          info->bmiHeader.biHeight = -bitmap.height;
427          info->bmiHeader.biBitCount = 32;
428          // If transparent, we need to create a black mask for the little GDI trick
429          if(bitmap.transparent)
430          {
431             Bitmap mask { };
432             HGDIOBJ prevDC;//, prevDC2;
433             int c;
434             mask.Allocate(null, bitmap.width, bitmap.height, 0, pixelFormat888, false);
435             for(c = 0; c<bitmap.width * bitmap.height; c++)
436                ((Color *)mask.picture)[c] = ((ColorAlpha *)bitmap.picture)[c].a ? 0xFFFFFF : 0;
437
438             gdiBitmap.bmp = CreateDIBitmap(gdiSystem.hdc, (LPBITMAPINFOHEADER)info, CBM_INIT, mask.picture, info, DIB_RGB_COLORS);
439             gdiBitmap.mask = CreateBitmap(bitmap.width, bitmap.height, 1, 1, null);
440             prevDC = SelectObject(gdiSystem.bmpDC, gdiBitmap.bmp);
441             /*prevDC2 = */SelectObject(gdiSystem.tmpDC, gdiBitmap.mask);
442             SetBkColor(gdiSystem.bmpDC, 0);
443             BitBlt(gdiSystem.tmpDC, 0, 0, bitmap.width, bitmap.height, gdiSystem.bmpDC, 0, 0, SRCCOPY);
444             SetBkColor(gdiSystem.bmpDC, 0);
445             SetTextColor(gdiSystem.bmpDC, 0xFFFFFF);
446
447             SelectObject(gdiSystem.bmpDC, prevDC);
448             DeleteObject(gdiBitmap.bmp);
449
450             gdiBitmap.bmp = CreateDIBitmap(gdiSystem.hdc, (LPBITMAPINFOHEADER)info, CBM_INIT, bitmap.picture, info, DIB_RGB_COLORS);
451             prevDC = SelectObject(gdiSystem.bmpDC, gdiBitmap.bmp);
452
453             /*
454             SetTextColor(gdiSystem.bmpDC, RGB(255,255,255));
455             SetBkColor(gdiSystem.bmpDC, RGB(0,0,0));
456             BitBlt(gdiSystem.bmpDC, 0, 0, bitmap.width, bitmap.height, gdiSystem.tmpDC, 0, 0, SRCAND);
457             SelectObject(gdiSystem.tmpDC, prevDC2);
458             SelectObject(gdiSystem.bmpDC, prevDC);
459             SetTextColor(gdiSystem.bmpDC, RGB(0,0,0));
460             SetBkColor(gdiSystem.bmpDC, RGB(255,255,255));
461             SetBkColor(gdiSystem.tmpDC, RGB(255,255,255));
462             */
463             delete mask;
464          }
465          else
466          {
467             gdiBitmap.bmp = CreateDIBitmap(gdiSystem.hdc, (LPBITMAPINFOHEADER)info, CBM_INIT, bitmap.picture, info, DIB_RGB_COLORS);
468          }
469
470          delete bitmap.picture;
471          delete info;
472
473          bitmap.driver = ((subclass(DisplayDriver))class(Win32PrinterDisplayDriver));
474          return true;
475       }
476       return false;
477    }
478
479    void ReleaseSurface(Display display, Surface surface)
480    {
481       Win32PrinterSurface gdiSurface = surface.driverData;
482       if(gdiSurface)
483       {
484          if(gdiSurface.rgn)
485          {
486             SelectClipRgn(gdiSurface.hdc,null);
487             DeleteObject(gdiSurface.rgn);
488             gdiSurface.rgn = null;
489          }
490          // ((subclass(DisplayDriver))class(LFBDisplayDriver)).ReleaseSurface(display, surface);
491          delete gdiSurface;
492          surface.driverData = null;
493       }
494    }
495
496    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
497    {
498       return false;
499    }
500
501    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
502    {
503       bool result = false;
504       Win32PrinterDisplay gdiDisplay = display.driverData;
505       if(gdiDisplay && !gdiDisplay.completed)
506       {
507          Win32PrinterSurface gdiSurface;
508          Win32PrinterSystem gdiSystem = display.displaySystem.driverData;
509
510          if((surface.driverData = gdiSurface = Win32PrinterSurface { }))
511          {
512             // if(((subclass(DisplayDriver))class(LFBDisplayDriver)).GetSurface(display, surface, x, y, clip))
513             {
514                gdiSurface.hdc = gdiDisplay.hdc ? gdiDisplay.hdc : gdiSystem.tmpDC;
515
516                gdiSurface.offset.x = x;
517                gdiSurface.offset.y = y;
518                gdiSurface.unclippedBox = gdiSurface.box = clip;
519
520                surface.width = gdiDisplay.width - x + 1;
521                surface.height = gdiDisplay.height - y + 1;
522                surface.offset.x = x * gdiDisplay.width / display.width;
523                surface.offset.y = y * gdiDisplay.height / display.height;
524                surface.unclippedBox = surface.box =
525                {
526                   left = clip.left * gdiDisplay.width / display.width,
527                   top = clip.top * gdiDisplay.height / display.height,
528                   right = (clip.right+1) * gdiDisplay.width / display.width-1,
529                   bottom = (clip.bottom+1) * gdiDisplay.height / display.height-1
530                };
531
532                gdiSurface.rgn = CreateRectRgn(
533                   surface.offset.x + surface.box.left,
534                   surface.offset.y + surface.box.top,
535                   surface.offset.x + surface.box.right + 1,
536                   surface.offset.y + surface.box.bottom + 1);
537
538                // x + clip.left, y+clip.top,x+clip.right+1,y+clip.bottom+1);
539
540                if(gdiSurface.rgn)
541                   SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
542
543                SetDCBrushColor(gdiSurface.hdc, RGB(0,0,0));
544                SetDCPenColor(gdiSurface.hdc, RGB(255,255,255));
545
546                SetBkColor(gdiSystem.hdc, RGB(0,0,0));
547
548                result = true;
549             }
550          }
551       }
552       return result;
553    }
554
555    void Clip(Display display, Surface surface, Box clip)
556    {
557       Win32PrinterDisplay gdiDisplay = display.driverData;
558       Win32PrinterSurface gdiSurface = surface.driverData;
559       HRGN clippedRgn = null;
560       if(clip != null)
561       {
562          Box box = clip;
563
564          box.Clip(gdiSurface.unclippedBox);
565
566          gdiSurface.box = box;
567          surface.box =
568          {
569             left = box.left * gdiDisplay.width / display.width,
570             top = box.top * gdiDisplay.height / display.height,
571             right = (box.right+1) * gdiDisplay.width / display.width-1,
572             bottom = (box.bottom+1) * gdiDisplay.height / display.height-1
573          };
574
575          if(box.right > box.left && box.bottom > box.top)
576          {
577             box.left += gdiSurface.offset.x;
578             box.top  += gdiSurface.offset.y;
579             box.right+= gdiSurface.offset.x;
580             box.bottom += gdiSurface.offset.y;
581
582             gdiSurface.rgn = CreateRectRgn(
583                surface.offset.x + surface.box.left,
584                surface.offset.y + surface.box.top,
585                surface.offset.x + surface.box.right + 1,
586                surface.offset.y + surface.box.bottom + 1);
587
588             // clippedRgn = CreateRectRgn(box.left, box.top, box.right+1, box.bottom+1);
589          }
590          else
591             clippedRgn = CreateRectRgn(0, 0, 0, 0);
592
593          if(clippedRgn)
594             SelectClipRgn(gdiSurface.hdc, clippedRgn);
595       }
596       else if(gdiSurface.clippedRgn)
597       {
598          surface.box = surface.unclippedBox;
599          gdiSurface.box = gdiSurface.unclippedBox;
600          SelectClipRgn(gdiSurface.hdc,gdiSurface.rgn);
601       }
602       if(gdiSurface.clippedRgn)
603          DeleteObject(gdiSurface.clippedRgn);
604       gdiSurface.clippedRgn = clippedRgn;
605    }
606
607    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
608    {
609       bool result = false;
610       // result = ((subclass(DisplayDriver))class(LFBDisplayDriver)).GrabScreen(display, bitmap, x,y, w,h);
611       return result;
612    }
613
614    void SetForeground(Display display, Surface surface, ColorAlpha color)
615    {
616       Win32PrinterSurface gdiSurface = surface.driverData;
617       COLORREF rgb = RGB(color.color.r, color.color.g, color.color.b);
618       // ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetForeground(display, surface, color);
619       SetTextColor(gdiSurface.hdc, rgb);
620       gdiSurface.color = rgb;
621       SetDCPenColor(gdiSurface.hdc, rgb);
622    }
623
624    void SetBackground(Display display, Surface surface, ColorAlpha color)
625    {
626       Win32PrinterSurface gdiSurface = surface.driverData;
627       COLORREF rgb;
628       /*
629       ((subclass(DisplayDriver))class(LFBDisplayDriver)).SetBackground(display, surface, color);
630       if(gdiSurface.bitmap.pixelFormat == pixelFormat8 && display)
631          color = gdiSurface.bitmap.palette[gdiDisplay.rgbLookup[(uint16)(Color555) color]];
632       */
633       rgb = RGB(color.color.r, color.color.g, color.color.b);
634       gdiSurface.backColor = rgb;
635       SetBkColor(gdiSurface.hdc, rgb);
636       SetDCBrushColor(gdiSurface.hdc, rgb);
637    }
638
639    ColorAlpha GetPixel(Display display, Surface surface, int x, int y)
640    {
641       return 0;
642    }
643
644    void PutPixel(Display display, Surface surface, int x, int y)
645    {
646       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
647       Win32PrinterSurface gdiSurface = surface.driverData;
648
649       SetBkMode(gdiSurface.hdc, OPAQUE);
650       SetBkColor(gdiSurface.hdc, gdiSurface.color);
651       PatBlt(gdiSurface.hdc,
652          (int)((float)x * gdiDisplay.width / display.width) + surface.offset.x,
653          (int)((float)y * gdiDisplay.height / display.height) + surface.offset.y,
654          (int)((float)(x+1) * gdiDisplay.width / display.width)-1 + surface.offset.x+1,
655          (int)((float)(y+1) * gdiDisplay.height / display.height)-1 + surface.offset.y+1,
656          PATCOPY);
657       SetBkColor(gdiSurface.hdc, gdiSurface.backColor);
658       SetBkMode(gdiSurface.hdc, surface.textOpacity ? OPAQUE : TRANSPARENT);
659    }
660
661    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
662    {
663       Win32PrinterSurface gdiSurface = surface.driverData;
664       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
665       int c = 0;
666
667       x1 = (int)((float)x1 * gdiDisplay.width / display.width) + surface.offset.x;
668       y1 = (int)((float)y1 * gdiDisplay.height / display.height) + surface.offset.y;
669       x2 = (int)((float)x2 * gdiDisplay.width / display.width) + surface.offset.x;
670       y2 = (int)((float)y2 * gdiDisplay.height / display.height) + surface.offset.y;
671       for(c = 0; c <= (float)gdiDisplay.width / display.width; c++)
672       {
673          if(x1 == x2)
674          {
675             MoveToEx(gdiSurface.hdc, x1, y1, null);
676             LineTo(gdiSurface.hdc, x2, y2 + (int)((float)gdiDisplay.width / display.width + 0.5)+1);
677             x1++;
678             x2++;
679          }
680          else if(y1 == y2)
681          {
682             MoveToEx(gdiSurface.hdc, x1, y1, null);
683             LineTo(gdiSurface.hdc, x2 + (int)((float)gdiDisplay.width / display.width + 0.5)+1, y2);
684             y1++;
685             y2++;
686          }
687          else
688          {
689             MoveToEx(gdiSurface.hdc, x1, y1, null);
690             LineTo(gdiSurface.hdc, x2 + (int)((float)gdiDisplay.width / display.width + 0.5)+1, y2 + (int)((float)gdiDisplay.width / display.width + 0.5)+1);
691             x1++;
692             x2++;
693          }
694       }
695    }
696
697    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
698    {
699       Win32PrinterSurface gdiSurface = surface.driverData;
700       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
701
702       int c;
703
704       SelectObject(gdiSurface.hdc,GetStockObject(NULL_BRUSH));
705       x1 = (int)((float)x1 * gdiDisplay.width / display.width) + surface.offset.x;
706       y1 = (int)((float)y1 * gdiDisplay.height / display.height) + surface.offset.y;
707       x2 = (int)((float)(x2) * gdiDisplay.width / display.width) + surface.offset.x;
708       y2 = (int)((float)(y2) * gdiDisplay.height / display.height) + surface.offset.y;
709       for(c = 0; c <= (float)gdiDisplay.width / display.width + 1.5; c++)
710       {
711          ::Rectangle(gdiSurface.hdc, x1, y1, x2, y2);
712          y1++; y2++;
713          x1++; x2++;
714       }
715       SelectObject(gdiSurface.hdc,GetStockObject(DC_BRUSH));
716    }
717
718    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
719    {
720       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
721       Win32PrinterSurface gdiSurface = surface.driverData;
722
723       x1 = (int)((float)x1 * gdiDisplay.width / display.width) + surface.offset.x;
724       y1 = (int)((float)y1 * gdiDisplay.height / display.height) + surface.offset.y;
725       x2 = (int)(((float)(x2+1) * gdiDisplay.width / display.width) + 0.5) + surface.offset.x;
726       y2 = (int)(((float)(y2+1) * gdiDisplay.height / display.height) + 0.5) + surface.offset.y;
727
728       SetBkMode(gdiSurface.hdc, OPAQUE);
729       SetBkColor(gdiSurface.hdc, gdiSurface.backColor);
730       SetDCBrushColor(gdiSurface.hdc, gdiSurface.backColor);
731       PatBlt(gdiSurface.hdc,x1,y1,x2-x1+1,y2-y1+1,PATCOPY);
732       SetBkMode(gdiSurface.hdc, surface.textOpacity ? OPAQUE : TRANSPARENT);
733    }
734
735    void Clear(Display display, Surface surface, ClearType type)
736    {
737       Win32PrinterSurface gdiSurface = surface.driverData;
738       if(type != depthBuffer)
739          Area(display, surface, gdiSurface.box.left, gdiSurface.box.top, gdiSurface.box.right, gdiSurface.box.bottom);
740    }
741
742    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
743    {
744       return true;
745    }
746
747    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
748    {
749       return false;
750    }
751
752    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
753    {
754       Filter(display, surface, src, dx, dy, sx, sy, w, h, w, h);
755    }
756
757    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
758    {
759       Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
760    }
761
762    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
763    {
764       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
765       Win32PrinterSystem gdiSystem = display.displaySystem.driverData;
766       Win32PrinterBitmap gdiBitmap = src.driverData;
767       Win32PrinterSurface gdiSurface = surface.driverData;
768
769       if(src.transparent)
770       {
771          SelectObject(gdiSystem.bmpDC, gdiBitmap.bmp);
772          SelectObject(gdiSystem.tmpDC, gdiBitmap.mask);
773
774          SetStretchBltMode(gdiSurface.hdc, HALFTONE); //COLORONCOLOR);
775
776          SetBkColor(gdiSurface.hdc, 0xFFFFFF);
777          SetTextColor(gdiSurface.hdc, 0);
778          StretchBlt(gdiSurface.hdc,
779             dx * gdiDisplay.width / display.width + surface.offset.x,
780             dy * gdiDisplay.height / display.height + surface.offset.y,
781             (w) * gdiDisplay.width / display.width,
782             (h) * gdiDisplay.height / display.height,
783             gdiSystem.tmpDC, sx, sy,sw,sh, SRCAND);
784          StretchBlt(gdiSurface.hdc,
785             dx * gdiDisplay.width / display.width + surface.offset.x,
786             dy * gdiDisplay.height / display.height + surface.offset.y,
787             (w) * gdiDisplay.width / display.width,
788             (h) * gdiDisplay.height / display.height,
789             gdiSystem.bmpDC, sx, sy,sw,sh, SRCPAINT);
790          /*
791          StretchBlt(gdiSurface.hdc,
792             dx * gdiDisplay.width / display.width + surface.offset.x,
793             dy * gdiDisplay.height / display.height + surface.offset.y,
794             (w+1) * gdiDisplay.width / display.width-1,
795             (h+1) * gdiDisplay.height / display.height-1,
796             gdiSystem.tmpDC, sx, sy,sw,sh, SRCAND);
797          StretchBlt(gdiSurface.hdc,
798             dx * gdiDisplay.width / display.width + surface.offset.x,
799             dy * gdiDisplay.height / display.height + surface.offset.y,
800             (w+1) * gdiDisplay.width / display.width-1,
801             (h+1) * gdiDisplay.height / display.height-1,
802             gdiSystem.bmpDC, sx, sy,sw,sh, SRCPAINT);
803          */
804          SetBkColor(gdiSurface.hdc, gdiSurface.backColor);
805       }
806       else
807       {
808          SetStretchBltMode(gdiSurface.hdc, HALFTONE); //COLORONCOLOR);
809          SelectObject(gdiSystem.bmpDC, gdiBitmap.bmp);
810          StretchBlt(gdiSurface.hdc,
811             dx * gdiDisplay.width / display.width + surface.offset.x,
812             dy * gdiDisplay.height / display.height + surface.offset.y,
813             (w+1) * gdiDisplay.width / display.width-1,
814             (h+1) * gdiDisplay.height / display.height-1,
815             gdiSystem.bmpDC, sx, sy,sw,sh, SRCCOPY);
816       }
817    }
818
819    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
820    {
821       Blit(display,surface,src,dx,dy,sx,sy,w,h);
822    }
823
824    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
825    {
826       Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
827    }
828
829    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
830    {
831       Filter(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
832    }
833
834    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
835    {
836       Win32PrinterSystem gdiSystem = displaySystem.driverData;
837       HDC hdc = gdiSystem.hdc;
838       int /*pixels, */res;
839       void * font;
840       /*
841       SetMapMode(gdiSystem.hdc, MM_ANISOTROPIC);
842       SetWindowExtEx(gdiSystem.hdc, RESX, RESY, null);
843       SetViewportExtEx(gdiSystem.hdc, GetDeviceCaps(gdiSystem.hdc, HORZRES), GetDeviceCaps(gdiSystem.hdc, VERTRES), null);
844       */
845
846       //pixels = GetDeviceCaps(hdc, VERTRES);
847       res = GetDeviceCaps(hdc, LOGPIXELSY);
848       {
849          int s;
850          s = -(int)(((float)size * res / 78) + 0.5);
851
852          // font = CreateFont(-(int)(((float)size * 96 / 72) + 0.5),
853          font = CreateFontA(s,
854          // font = CreateFont(-(int)(((float)size * pixels * RESY / res / 72) + 0.5),
855             0,0,0, flags.bold ? FW_BOLD : FW_NORMAL, flags.italic ? TRUE : FALSE,
856                flags.underline ? TRUE : FALSE, 0, DEFAULT_CHARSET,
857                            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
858                            DEFAULT_PITCH|FF_DONTCARE, faceName);
859       }
860       // SetMapMode(gdiSystem.hdc, MM_TEXT);
861       return font;
862    }
863
864    void UnloadFont(DisplaySystem displaySystem, Font font)
865    {
866       if(font)
867          DeleteObject(font);
868    }
869
870    void TextFont(Display display, Surface surface, Font font)
871    {
872       Win32PrinterSurface gdiSurface = surface.driverData;
873       SelectObject(gdiSurface.hdc, font);
874    }
875
876    void TextOpacity(Display display, Surface surface, bool opaque)
877    {
878       Win32PrinterSurface gdiSurface = surface.driverData;
879       SetBkMode(gdiSurface.hdc, opaque ? OPAQUE : TRANSPARENT);
880    }
881
882    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
883    {
884       Win32PrinterSurface gdiSurface = surface.driverData;
885       Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
886       int wordCount;
887       uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
888
889       /*
890       SetMapMode(gdiSurface.hdc, MM_ANISOTROPIC);
891       SetWindowExtEx(gdiSurface.hdc, RESX, RESY, null);
892       SetViewportExtEx(gdiSurface.hdc, GetDeviceCaps(gdiSurface.hdc, HORZRES), GetDeviceCaps(gdiSurface.hdc, VERTRES), null);
893       */
894       TextOut(gdiSurface.hdc, x * gdiDisplay.width / display.width + surface.offset.x, y * gdiDisplay.height / display.height + surface.offset.y, u16text, wordCount);
895       /*
896       TextOut(gdiSurface.hdc, x + gdiSurface.offset.x, y + gdiSurface.offset.y, text,len);
897       SetMapMode(gdiSurface.hdc, MM_TEXT);
898       */
899       delete u16text;
900    }
901
902    void ::_TextExtent(HDC hdc, int resX, int resY, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
903    {
904       SIZE space, size;
905       uint realLen;
906       int wordCount;
907       uint16 * u16text = UTF8toUTF16Len(text, len, &wordCount);
908
909       for(realLen = 0; realLen<wordCount && u16text[realLen]; realLen++);
910       GetTextExtentPoint32(hdc, L" ", 1, &space);
911       GetTextExtentPoint32(hdc, u16text, realLen, &size);
912       delete u16text;
913
914       if(adv) *adv = 0;
915       if(width)
916       {
917           // UNICODE FIX: proper space computation
918           *width = size.cx + (wordCount - realLen) * space.cx;
919           *width = *width * resX / GetDeviceCaps(hdc, HORZRES);
920       }
921       if(height)
922       {
923          if(realLen)
924             *height = size.cy;
925          else
926             *height = len ? space.cy : 0;
927          *height = *height * resY / GetDeviceCaps(hdc, VERTRES);
928       }
929    }
930
931    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
932    {
933       Win32PrinterSystem gdiSystem = (display && display.displaySystem) ? display.displaySystem.driverData : null;
934       Win32PrinterSurface gdiSurface = surface.driverData;
935
936       _TextExtent(gdiSurface.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height, prevGlyph, rPrevGlyph, adv);
937    }
938
939    void FontExtent(DisplaySystem displaySystem, void * font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
940    {
941       Win32PrinterSystem gdiSystem = displaySystem.driverData;
942       if(gdiSystem.hdc)
943       {
944          SelectObject(gdiSystem.hdc, font);
945          _TextExtent(gdiSystem.hdc, gdiSystem.resX, gdiSystem.resY, text, len, width, height, prevGlyph, rPrevGlyph, adv);
946       }
947       else
948       {
949          if(width) *width = 0;
950          if(adv) *adv = 0;
951          if(height) *height = 0;
952       }
953    }
954
955    void DrawingChar(Display display, Surface surface, byte character)
956    {
957
958    }
959
960    void LineStipple(Display display, Surface surface, uint stipple)
961    {
962       //Win32PrinterDisplay gdiDisplay = display ? display.driverData : null;
963       // ((subclass(DisplayDriver))class(LFBDisplayDriver)).LineStipple(display, surface, stipple);
964    }
965
966    bool Lock(Display display)
967    {
968       return true;
969    }
970
971    void Unlock(Display display)
972    {
973    }
974 }
975
976 #endif