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