xref: /trunk/main/vcl/os2/source/gdi/salgdi.cxx (revision 9f62ea84a806e17e6f2bbff75724a7257a0eb5d9)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include <string.h>
25 #include <svpm.h>
26 
27 #define _SV_SALGDI_CXX
28 #include <tools/debug.hxx>
29 #include <saldata.hxx>
30 #include <salgdi.h>
31 #include <tools/debug.hxx>
32 #include <salframe.h>
33 #include <tools/poly.hxx>
34 #ifndef _RTL_STRINGBUF_HXX
35 #include <rtl/strbuf.hxx>
36 #endif
37 #include "vcl/region.h"
38 
39 #ifndef __H_FT2LIB
40 #include <wingdi.h>
41 #include <ft2lib.h>
42 #endif
43 
44 // -----------
45 // - Defines -
46 // -----------
47 
48 // ClipRegions funktionieren immer noch nicht auf allen getesteten Druckern
49 #define SAL_PRINTER_CLIPPATH    1
50 // #define SAL_PRINTER_POLYPATH 1
51 
52 // =======================================================================
53 
54 void ImplInitSalGDI()
55 {
56 }
57 
58 // -----------------------------------------------------------------------
59 
60 void ImplFreeSalGDI()
61 {
62     SalData*    pSalData = GetSalData();
63 
64     // delete icon cache
65     SalIcon* pIcon = pSalData->mpFirstIcon;
66     while( pIcon )
67     {
68         SalIcon* pTmp = pIcon->pNext;
69         WinDestroyPointer( pIcon->hIcon );
70         delete pIcon;
71         pIcon = pTmp;
72     }
73 
74 }
75 
76 // =======================================================================
77 
78 void ImplSalInitGraphics( Os2SalGraphics* pData )
79 {
80     GpiCreateLogColorTable( pData->mhPS, LCOL_RESET, LCOLF_RGB, 0, 0, NULL );
81 }
82 
83 // -----------------------------------------------------------------------
84 
85 void ImplSalDeInitGraphics( Os2SalGraphics* pData )
86 {
87 }
88 
89 // =======================================================================
90 
91 Os2SalGraphics::Os2SalGraphics()
92 {
93     for( int i = 0; i < MAX_FALLBACK; ++i )
94     {
95         mhFonts[ i ] = 0;
96         mpOs2FontData[ i ]  = NULL;
97         mpOs2FontEntry[ i ] = NULL;
98     }
99 
100     mfFontScale = 1.0;
101 
102     mhPS            = 0;
103     mhDC            = 0;
104     mbLine              = FALSE;
105     mbFill              = FALSE;
106     mbXORMode           = FALSE;
107     mnFontMetricCount   = 0;
108     mpFontMetrics       = NULL;
109     mpClipRectlAry      = NULL;
110 
111     mhDefFont           = 0;
112     mpFontKernPairs     = NULL;
113     mnFontKernPairCount = 0;
114     mbFontKernInit      = FALSE;
115 
116 }
117 
118 // -----------------------------------------------------------------------
119 
120 Os2SalGraphics::~Os2SalGraphics()
121 {
122     Ft2DeleteSetId( mhPS, LCID_BASE);
123 
124     if ( mpFontMetrics )
125         delete mpFontMetrics;
126 
127     if ( mpFontKernPairs )
128         delete mpFontKernPairs;
129 
130 }
131 
132 // -----------------------------------------------------------------------
133 
134 static SalColor ImplGetROPSalColor( SalROPColor nROPColor )
135 {
136     SalColor nSalColor;
137 
138     switch( nROPColor )
139     {
140         case SAL_ROP_0:
141             nSalColor = MAKE_SALCOLOR( 0, 0, 0 );
142         break;
143 
144         case SAL_ROP_1:
145         case SAL_ROP_INVERT:
146             nSalColor = MAKE_SALCOLOR( 255, 255, 255 );
147         break;
148     }
149 
150     return nSalColor;
151 }
152 
153 // -----------------------------------------------------------------------
154 
155 void Os2SalGraphics::GetResolution( long& rDPIX, long& rDPIY )
156 {
157     // since OOo asks for DPI, I will query FONT_RES, which seems to be
158     // more correct than _RESOLUTION fields (on my wide screen lcd)
159     // and does not require conversion
160     DevQueryCaps( mhDC, CAPS_HORIZONTAL_FONT_RES, 1, &rDPIX );
161     DevQueryCaps( mhDC, CAPS_VERTICAL_FONT_RES, 1, &rDPIY );
162 }
163 
164 // -----------------------------------------------------------------------
165 
166 USHORT Os2SalGraphics::GetBitCount()
167 {
168     LONG nBitCount;
169     DevQueryCaps( mhDC, CAPS_COLOR_BITCOUNT, 1, &nBitCount );
170     return (USHORT)nBitCount;
171 }
172 
173 // -----------------------------------------------------------------------
174 
175 long Os2SalGraphics::GetGraphicsWidth() const
176 {
177     if( mhWnd )
178     {
179         Os2SalFrame* pFrame = (Os2SalFrame*)GetWindowPtr( mhWnd );
180         if( pFrame )
181         {
182             if( pFrame->maGeometry.nWidth )
183                 return pFrame->maGeometry.nWidth;
184             else
185             {
186                 // TODO: perhaps not needed, maGeometry should always be up-to-date
187                 RECTL aRect;
188                 WinQueryWindowRect( mhWnd, &aRect );
189                 return aRect.xRight;
190             }
191         }
192     }
193 
194     return 0;
195 }
196 
197 // -----------------------------------------------------------------------
198 
199 void Os2SalGraphics::ResetClipRegion()
200 {
201 #ifdef SAL_PRINTER_CLIPPATH
202     if ( mbPrinter )
203         GpiSetClipPath( mhPS, 0, SCP_RESET );
204     else
205 #endif
206     {
207         HRGN hOldRegion;
208 
209         GpiSetClipRegion( mhPS, NULL, &hOldRegion );
210         if ( hOldRegion )
211             GpiDestroyRegion( mhPS, hOldRegion );
212     }
213 }
214 
215 // -----------------------------------------------------------------------
216 
217 bool Os2SalGraphics::setClipRegion( const Region& i_rClip )
218 {
219     ULONG nCount = i_rClip.GetRectCount();
220 
221     mpClipRectlAry    = new RECTL[ nCount ];
222     mnClipElementCount = 0;
223 
224     ImplRegionInfo aInfo;
225     long nX, nY, nW, nH;
226     bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH );
227     while( bRegionRect )
228     {
229         if ( nW && nH )
230         {
231             RECTL* pClipRect = &mpClipRectlAry[ mnClipElementCount ];
232             pClipRect->xLeft   = nX;
233             pClipRect->yTop    = mnHeight - nY;
234             pClipRect->xRight  = nX + nW;
235             pClipRect->yBottom = mnHeight - (nY + nH);
236             mnClipElementCount++;
237         }
238         bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH );
239     }
240 #ifdef SAL_PRINTER_CLIPPATH
241     if ( mbPrinter )
242     {
243         GpiSetClipPath( mhPS, 0, SCP_RESET );
244         GpiBeginPath( mhPS, 1L );
245 
246         for( int i = 0; i < mnClipElementCount; i++ )
247         {
248             POINTL aPt;
249             RECTL* pClipRect = &mpClipRectlAry[ i ];
250 
251             aPt.x = pClipRect->xLeft;
252             aPt.y = pClipRect->yTop-1;
253             Ft2Move( mhPS, &aPt );
254 
255             aPt.x = pClipRect->xRight-1;
256             aPt.y = pClipRect->yBottom;
257 
258             Ft2Box( mhPS, DRO_OUTLINE, &aPt, 0, 0 );
259         }
260 
261         GpiEndPath( mhPS );
262         GpiSetClipPath( mhPS, 1L, SCP_ALTERNATE | SCP_AND );
263     }
264     else
265 #endif
266     {
267         HRGN hClipRegion = GpiCreateRegion( mhPS,
268                                             mnClipElementCount,
269                                             mpClipRectlAry );
270         HRGN hOldRegion;
271 
272         GpiSetClipRegion( mhPS, hClipRegion, &hOldRegion );
273         if( hOldRegion )
274             GpiDestroyRegion( mhPS, hOldRegion );
275     }
276 
277     delete [] mpClipRectlAry;
278 
279     return true;
280 }
281 
282 // -----------------------------------------------------------------------
283 
284 void Os2SalGraphics::SetLineColor()
285 {
286     // don't draw line!
287     mbLine = FALSE;
288 }
289 
290 // -----------------------------------------------------------------------
291 
292 void Os2SalGraphics::SetLineColor( SalColor nSalColor )
293 {
294     LINEBUNDLE lb;
295 
296     // set color
297     lb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
298                           SALCOLOR_GREEN( nSalColor ),
299                           SALCOLOR_BLUE( nSalColor ) );
300 
301     Ft2SetAttrs( mhPS,
302                  PRIM_LINE,
303                  LBB_COLOR,
304                  0,
305                  &lb );
306 
307     // draw line!
308     mbLine = TRUE;
309 }
310 
311 // -----------------------------------------------------------------------
312 
313 void Os2SalGraphics::SetFillColor()
314 {
315     // don't fill area!
316     mbFill = FALSE;
317 }
318 
319 // -----------------------------------------------------------------------
320 
321 void Os2SalGraphics::SetFillColor( SalColor nSalColor )
322 {
323     AREABUNDLE ab;
324 
325     // set color
326     ab.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
327                           SALCOLOR_GREEN( nSalColor ),
328                           SALCOLOR_BLUE( nSalColor ) );
329 
330     Ft2SetAttrs( mhPS,
331                  PRIM_AREA,
332                  ABB_COLOR,
333                  0,
334                  &ab );
335 
336     // fill area!
337     mbFill = TRUE;
338 }
339 
340 // -----------------------------------------------------------------------
341 
342 void Os2SalGraphics::SetXORMode( bool bSet, bool )
343 {
344     mbXORMode = bSet;
345     LONG nMixMode = bSet ? FM_XOR : FM_OVERPAINT;
346 
347     // set mix mode for lines
348     LINEBUNDLE lb;
349     lb.usMixMode = nMixMode;
350     Ft2SetAttrs( mhPS,
351                  PRIM_LINE,
352                  LBB_MIX_MODE,
353                  0,
354                  &lb );
355 
356     // set mix mode for areas
357     AREABUNDLE ab;
358     ab.usMixMode = nMixMode;
359     Ft2SetAttrs( mhPS,
360                  PRIM_AREA,
361                  ABB_MIX_MODE,
362                  0,
363                  &ab );
364 
365     // set mix mode for text
366     CHARBUNDLE cb;
367     cb.usMixMode = nMixMode;
368     Ft2SetAttrs( mhPS,
369                  PRIM_CHAR,
370                  CBB_MIX_MODE,
371                  0,
372                  &cb );
373 }
374 
375 // -----------------------------------------------------------------------
376 
377 void Os2SalGraphics::SetROPLineColor( SalROPColor nROPColor )
378 {
379     SetLineColor( ImplGetROPSalColor( nROPColor ) );
380 }
381 
382 // -----------------------------------------------------------------------
383 
384 void Os2SalGraphics::SetROPFillColor( SalROPColor nROPColor )
385 {
386     SetFillColor( ImplGetROPSalColor( nROPColor ) );
387 }
388 
389 // -----------------------------------------------------------------------
390 
391 void Os2SalGraphics::drawPixel( long nX, long nY )
392 {
393     POINTL aPt;
394 
395     aPt.x = nX;
396     aPt.y = TY( nY );
397 
398     // set color
399     Ft2SetPel( mhPS, &aPt );
400 }
401 
402 // -----------------------------------------------------------------------
403 
404 void Os2SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor )
405 {
406     // save old color
407     LINEBUNDLE oldLb;
408     GpiQueryAttrs( mhPS,
409                    PRIM_LINE,
410                    LBB_COLOR,
411                    &oldLb );
412 
413     // set new color
414     LINEBUNDLE lb;
415     lb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
416                           SALCOLOR_GREEN( nSalColor ),
417                           SALCOLOR_BLUE( nSalColor ) );
418     Ft2SetAttrs( mhPS,
419                  PRIM_LINE,
420                  LBB_COLOR,
421                  0,
422                  &lb );
423 
424     // set color of pixel
425     POINTL aPt;
426     aPt.x = nX;
427     aPt.y = TY( nY );
428     Ft2SetPel( mhPS, &aPt );
429 
430     // restore old color
431     Ft2SetAttrs( mhPS,
432                  PRIM_LINE,
433                  LBB_COLOR,
434                  0,
435                  &oldLb );
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 void Os2SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 )
441 {
442     // OS2 zeichnet den Endpunkt mit
443     POINTL aPt;
444     aPt.x = nX1;
445     aPt.y = TY( nY1 );
446     Ft2Move( mhPS, &aPt );
447     aPt.x = nX2;
448     aPt.y = TY( nY2 );
449     GpiLine( mhPS, &aPt );
450 }
451 
452 // -----------------------------------------------------------------------
453 
454 void Os2SalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
455 {
456     POINTL aPt;
457     long lControl;
458 
459     if ( mbFill )
460     {
461         if ( mbLine )
462             lControl = DRO_OUTLINEFILL;
463         else
464             lControl = DRO_FILL;
465     }
466     else
467     {
468         if ( mbLine )
469             lControl = DRO_OUTLINE;
470         else
471             return;
472     }
473 
474     aPt.x = nX;
475     aPt.y = TY( nY );
476     Ft2Move( mhPS, &aPt );
477     aPt.x = nX + nWidth - 1;
478     aPt.y = TY( nY + nHeight - 1 );
479     Ft2Box( mhPS, lControl, &aPt, 0, 0 );
480 }
481 
482 // -----------------------------------------------------------------------
483 
484 void Os2SalGraphics::drawPolyLine( ULONG nPoints, const SalPoint* pPtAry )
485 {
486     // convert all points to sys orientation
487     POINTL*             pOS2PtAry = new POINTL[ nPoints ];
488     POINTL*             pTempOS2PtAry = pOS2PtAry;
489     const SalPoint*     pTempPtAry = pPtAry;
490     ULONG               nTempPoints = nPoints;
491     long                nHeight = mnHeight - 1;
492 
493     while( nTempPoints-- )
494     {
495         (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
496         (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
497         pTempOS2PtAry++;
498         pTempPtAry++;
499     }
500 
501     Ft2Move( mhPS, pOS2PtAry );
502     GpiPolyLine( mhPS, nPoints, pOS2PtAry );
503     delete [] pOS2PtAry;
504 }
505 
506 // -----------------------------------------------------------------------
507 
508 void Os2SalGraphics::drawPolygon( ULONG nPoints, const SalPoint* pPtAry )
509 {
510     PM_POLYGON aPolygon;
511 
512     // create polygon
513     aPolygon.aPointl = new POINTL[ nPoints ];
514     aPolygon.ulPoints = nPoints;
515 
516     // convert all points to sys orientation
517     POINTL*             pTempOS2PtAry = aPolygon.aPointl;
518     const SalPoint*     pTempPtAry = pPtAry;
519     ULONG               nTempPoints = nPoints;
520     long                nHeight = mnHeight - 1;
521 
522     while( nTempPoints-- )
523     {
524         (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
525         (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
526         pTempOS2PtAry++;
527         pTempPtAry++;
528     }
529 
530     // Innenleben zeichnen
531     if ( mbFill )
532     {
533 #ifdef SAL_PRINTER_POLYPATH
534         if ( mbPrinter )
535         {
536             Ft2BeginPath( mhPS, 1 );
537             Ft2Move( mhPS, aPolygon.aPointl );
538             Ft2PolyLine( mhPS, aPolygon.ulPoints, aPolygon.aPointl );
539             Ft2EndPath( mhPS );
540             Ft2FillPath( mhPS, 1, 0 );
541 
542             if ( mbLine )
543             {
544                 Ft2Move( mhPS, aPolygon.aPointl );
545                 Ft2PolyLine( mhPS, aPolygon.ulPoints, aPolygon.aPointl );
546             }
547         }
548         else
549 #endif
550         {
551             ULONG nOptions = POLYGON_ALTERNATE;
552 
553             if ( mbLine )
554                 nOptions |= POLYGON_BOUNDARY;
555             else
556                 nOptions |= POLYGON_NOBOUNDARY;
557 
558             Ft2Move( mhPS, aPolygon.aPointl );
559             GpiPolygons( mhPS, 1, &aPolygon, nOptions, POLYGON_EXCL );
560         }
561     }
562     else
563     {
564         if ( mbLine )
565         {
566             Ft2Move( mhPS, aPolygon.aPointl );
567             GpiPolyLine( mhPS, nPoints, aPolygon.aPointl );
568         }
569     }
570 
571     delete [] aPolygon.aPointl;
572 }
573 
574 // -----------------------------------------------------------------------
575 
576 void Os2SalGraphics::drawPolyPolygon( ULONG nPoly, const ULONG* pPoints,
577                                    PCONSTSALPOINT* pPtAry )
578 {
579     ULONG       i;
580     long        nHeight = mnHeight - 1;
581     PM_POLYGON* aPolygonAry = new PM_POLYGON[ nPoly ];
582 
583     for( i = 0; i < nPoly; i++ )
584     {
585         const SalPoint * pTempPtAry = (const SalPoint*)pPtAry[ i ];
586 
587         // create polygon
588         ULONG nTempPoints = pPoints[ i ];
589         POINTL * pTempOS2PtAry = new POINTL[ nTempPoints ];
590 
591         // convert all points to sys orientation
592         aPolygonAry[ i ].ulPoints = nTempPoints;
593         aPolygonAry[ i ].aPointl = pTempOS2PtAry;
594 
595         while( nTempPoints-- )
596         {
597             (*pTempOS2PtAry).x = (*pTempPtAry).mnX;
598             (*pTempOS2PtAry).y = nHeight - (*pTempPtAry).mnY;
599             pTempOS2PtAry++;
600             pTempPtAry++;
601         }
602     }
603 
604     // Innenleben zeichnen
605     if ( mbFill )
606     {
607 #ifdef SAL_PRINTER_POLYPATH
608         if ( mbPrinter )
609         {
610             Ft2BeginPath( mhPS, 1 );
611             for ( i = 0; i < nPoly; i++ )
612             {
613                 Ft2Move( mhPS, aPolygonAry[i].aPointl );
614                 Ft2PolyLine( mhPS, aPolygonAry[i].ulPoints, aPolygonAry[i].aPointl );
615             }
616             Ft2EndPath( mhPS );
617             Ft2FillPath( mhPS, 1, 0 );
618         }
619         else
620 #endif
621         {
622             ULONG nOptions = POLYGON_ALTERNATE;
623 
624             if ( mbLine )
625                 nOptions |= POLYGON_BOUNDARY;
626             else
627                 nOptions |= POLYGON_NOBOUNDARY;
628 
629             Ft2Move( mhPS, aPolygonAry[ 0 ].aPointl );
630             GpiPolygons( mhPS, nPoly, aPolygonAry, nOptions, POLYGON_EXCL );
631         }
632     }
633     else
634     {
635         if ( mbLine )
636         {
637             for( i = 0; i < nPoly; i++ )
638             {
639                 Ft2Move( mhPS, aPolygonAry[ i ].aPointl );
640                 GpiPolyLine( mhPS, aPolygonAry[ i ].ulPoints, aPolygonAry[ i ].aPointl );
641             }
642         }
643     }
644 
645     // cleanup
646     for( i = 0; i < nPoly; i++ )
647         delete [] aPolygonAry[ i ].aPointl;
648     delete [] aPolygonAry;
649 }
650 
651 // -----------------------------------------------------------------------
652 
653 bool Os2SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
654 {
655     // TODO: implement and advertise OutDevSupport_B2DDraw support
656     return false;
657 }
658 
659 // -----------------------------------------------------------------------
660 
661 bool Os2SalGraphics::drawPolyLine(
662     const basegfx::B2DPolygon& /*rPolygon*/,
663     double /*fTransparency*/,
664     const basegfx::B2DVector& /*rLineWidths*/,
665     basegfx::B2DLineJoin /*eLineJoin*/)
666 {
667     // TODO: implement
668     return false;
669 }
670 
671 // -----------------------------------------------------------------------
672 
673 sal_Bool Os2SalGraphics::drawPolyLineBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
674 {
675     return sal_False;
676 }
677 
678 // -----------------------------------------------------------------------
679 
680 sal_Bool Os2SalGraphics::drawPolygonBezier( ULONG nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry )
681 {
682     return sal_False;
683 }
684 
685 // -----------------------------------------------------------------------
686 
687 sal_Bool Os2SalGraphics::drawPolyPolygonBezier( ULONG nPoly, const ULONG* pPoints,
688                                              const SalPoint* const* pPtAry, const BYTE* const* pFlgAry )
689 {
690     return sal_False;
691 }
692 
693 // =======================================================================
694 
695 // MAXIMUM BUFSIZE EQ 0xFFFF
696 #define POSTSCRIPT_BUFSIZE          0x4000
697 // we only try to get the BoundingBox in the first 4096 bytes
698 #define POSTSCRIPT_BOUNDINGSEARCH   0x1000
699 
700 static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, ULONG nComp, ULONG nSize )
701 {
702     while ( nComp-- >= nSize )
703     {
704         ULONG   i;
705         for ( i = 0; i < nSize; i++ )
706         {
707             if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
708                 break;
709         }
710         if ( i == nSize )
711             return pSource;
712         pSource++;
713     }
714     return NULL;
715 }
716 
717 
718 static BOOL ImplGetBoundingBox( double* nNumb, BYTE* pSource, ULONG nSize )
719 {
720     BOOL    bRetValue = FALSE;
721     BYTE* pDest = ImplSearchEntry( pSource, (BYTE*)"%%BoundingBox:", nSize, 14 );
722     if ( pDest )
723     {
724         nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
725         pDest += 14;
726 
727         int nSizeLeft = nSize - ( pDest - pSource );
728         if ( nSizeLeft > 100 )
729             nSizeLeft = 100;    // only 100 bytes following the bounding box will be checked
730 
731         int i;
732         for ( i = 0; ( i < 4 ) && nSizeLeft; i++ )
733         {
734             int     nDivision = 1;
735             BOOL    bDivision = FALSE;
736             BOOL    bNegative = FALSE;
737             BOOL    bValid = TRUE;
738 
739             while ( ( --nSizeLeft ) && ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) pDest++;
740             BYTE nByte = *pDest;
741             while ( nSizeLeft && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
742             {
743                 switch ( nByte )
744                 {
745                     case '.' :
746                         if ( bDivision )
747                             bValid = FALSE;
748                         else
749                             bDivision = TRUE;
750                         break;
751                     case '-' :
752                         bNegative = TRUE;
753                         break;
754                     default :
755                         if ( ( nByte < '0' ) || ( nByte > '9' ) )
756                             nSizeLeft = 1;  // error parsing the bounding box values
757                         else if ( bValid )
758                         {
759                             if ( bDivision )
760                                 nDivision*=10;
761                             nNumb[i] *= 10;
762                             nNumb[i] += nByte - '0';
763                         }
764                         break;
765                 }
766                 nSizeLeft--;
767                 nByte = *(++pDest);
768             }
769             if ( bNegative )
770                 nNumb[i] = -nNumb[i];
771             if ( bDivision && ( nDivision != 1 ) )
772                 nNumb[i] /= nDivision;
773         }
774         if ( i == 4 )
775             bRetValue = TRUE;
776     }
777     return bRetValue;
778 }
779 
780 #if 0
781 static void ImplWriteDouble( BYTE** pBuf, double nNumber )
782 {
783 //  *pBuf += sprintf( (char*)*pBuf, "%f", nNumber );
784 
785     if ( nNumber < 0 )
786     {
787         *(*pBuf)++ = (BYTE)'-';
788         nNumber = -nNumber;
789     }
790     ULONG nTemp = (ULONG)nNumber;
791     const String aNumber1( nTemp );
792     ULONG nLen = aNumber1.Len();
793 
794     for ( USHORT n = 0; n < nLen; n++ )
795         *(*pBuf)++ = aNumber1[ n ];
796 
797     nTemp = (ULONG)( ( nNumber - nTemp ) * 100000 );
798     if ( nTemp )
799     {
800         *(*pBuf)++ = (BYTE)'.';
801         const String aNumber2( nTemp );
802 
803         ULONG nLen = aNumber2.Len();
804         if ( nLen < 8 )
805         {
806             for ( n = 0; n < ( 5 - nLen ); n++ )
807             {
808                 *(*pBuf)++ = (BYTE)'0';
809             }
810         }
811         for ( USHORT n = 0; n < nLen; n++ )
812         {
813             *(*pBuf)++ = aNumber2[ n ];
814         }
815     }
816     *(*pBuf)++ = ' ';
817 }
818 #endif
819 
820 inline void ImplWriteString( BYTE** pBuf, const char* sString )
821 {
822     strcpy( (char*)*pBuf, sString );
823     *pBuf += strlen( sString );
824 }
825 
826 BOOL Os2SalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, ULONG nSize )
827 {
828     if ( !mbPrinter )
829         return FALSE;
830 
831     BOOL    bRet  = FALSE;
832     LONG    nLong = 0;
833     if ( !(DevQueryCaps( mhDC, CAPS_TECHNOLOGY, 1, &nLong ) &&
834            (CAPS_TECH_POSTSCRIPT == nLong)) )
835         return FALSE;
836 
837     BYTE*   pBuf = new BYTE[ POSTSCRIPT_BUFSIZE ];
838     double  nBoundingBox[4];
839 
840     if ( pBuf && ImplGetBoundingBox( nBoundingBox, (BYTE*)pPtr, nSize ) )
841     {
842         LONG pOS2DXAry[4];        // hack -> print always 2 white space
843         POINTL aPt;
844         aPt.x = 0;
845         aPt.y = 0;
846         PCH pStr = (PCH) "  ";
847         for( long i = 0; i < 4; i++ )
848             pOS2DXAry[i] = i;
849         Ft2CharStringPosAt( mhPS, &aPt, NULL, 0, 2, (PCH)pStr,(PLONG)&pOS2DXAry[0] );
850 
851         OStringBuffer aBuf( POSTSCRIPT_BUFSIZE );
852 
853                 // reserve place for a USHORT
854                 aBuf.append( "aa" );
855 
856                 // #107797# Write out EPS encapsulation header
857                 // ----------------------------------------------------------------------------------
858 
859                 // directly taken from the PLRM 3.0, p. 726. Note:
860                 // this will definitely cause problems when
861                 // recursively creating and embedding PostScript files
862                 // in OOo, since we use statically-named variables
863                 // here (namely, b4_Inc_state_salWin, dict_count_salWin and
864                 // op_count_salWin). Currently, I have no idea on how to
865                 // work around that, except from scanning and
866                 // interpreting the EPS for unused identifiers.
867 
868                 // append the real text
869                 aBuf.append( "\n\n/b4_Inc_state_salWin save def\n"
870                              "/dict_count_salWin countdictstack def\n"
871                              "/op_count_salWin count 1 sub def\n"
872                              "userdict begin\n"
873                              "/showpage {} def\n"
874                              "0 setgray 0 setlinecap\n"
875                              "1 setlinewidth 0 setlinejoin\n"
876                              "10 setmiterlimit [] 0 setdash newpath\n"
877                              "/languagelevel where\n"
878                              "{\n"
879                              "  pop languagelevel\n"
880                              "  1 ne\n"
881                              "  {\n"
882                              "    false setstrokeadjust false setoverprint\n"
883                              "  } if\n"
884                              "} if\n\n" );
885 
886 #if 0
887                 // #i10737# Apply clipping manually
888                 // ----------------------------------------------------------------------------------
889 
890                 // Windows seems to ignore any clipping at the HDC,
891                 // when followed by a POSTSCRIPT_PASSTHROUGH
892 
893                 // Check whether we've got a clipping, consisting of
894                 // exactly one rect (other cases should be, but aren't
895                 // handled currently)
896 
897                 // TODO: Handle more than one rectangle here (take
898                 // care, the buffer can handle only POSTSCRIPT_BUFSIZE
899                 // characters!)
900                 if ( mhRegion != 0 &&
901                      mpStdClipRgnData != NULL &&
902                      mpClipRgnData == mpStdClipRgnData &&
903                      mpClipRgnData->rdh.nCount == 1 )
904                 {
905                     RECT* pRect = &(mpClipRgnData->rdh.rcBound);
906 
907                     aBuf.append( "\nnewpath\n" );
908                     aBuf.append( pRect->left );
909                     aBuf.append( " " );
910                     aBuf.append( pRect->top );
911                     aBuf.append( " moveto\n" );
912                     aBuf.append( pRect->right );
913                     aBuf.append( " " );
914                     aBuf.append( pRect->top );
915                     aBuf.append( " lineto\n" );
916                     aBuf.append( pRect->right );
917                     aBuf.append( " " );
918                     aBuf.append( pRect->bottom );
919                     aBuf.append( " lineto\n" );
920                     aBuf.append( pRect->left );
921                     aBuf.append( " " );
922                     aBuf.append( pRect->bottom );
923                     aBuf.append( " lineto\n"
924                                  "closepath\n"
925                                  "clip\n"
926                                  "newpath\n" );
927                 }
928 #endif
929 
930                 // #107797# Write out buffer
931                 // ----------------------------------------------------------------------------------
932                 *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
933                 //Escape ( mhDC, nEscape, aBuf.getLength(), (LPTSTR)aBuf.getStr(), 0 );
934                 DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
935                         (PBYTE)aBuf.getStr(), 0, NULL );
936 
937         double dM11 = nWidth / ( nBoundingBox[2] - nBoundingBox[0] );
938         double dM22 = - ( nHeight / (nBoundingBox[1] - nBoundingBox[3] ) );
939 
940                 // reserve a USHORT again
941                 aBuf.setLength( 2 );
942                 aBuf.append( "\n\n[" );
943                 aBuf.append( dM11 );
944                 aBuf.append( " 0 0 " );
945                 aBuf.append( dM22 );
946                 aBuf.append( ' ' );
947                 aBuf.append( nX - ( dM11 * nBoundingBox[0] ) );
948                 aBuf.append( ' ' );
949                 aBuf.append( nY - ( dM22 * nBoundingBox[3] ) );
950                 aBuf.append( "] concat\n"
951                              "%%BeginDocument:\n" );
952                 *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
953                 DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
954                         (PBYTE)aBuf.getStr(), 0, NULL );
955 #if 0
956         BYTE* pTemp = pBuf;
957         ImplWriteString( &pTemp, "save\n[ " );
958         ImplWriteDouble( &pTemp, dM11 );
959         ImplWriteDouble( &pTemp, 0 );
960         ImplWriteDouble( &pTemp, 0 );
961         ImplWriteDouble( &pTemp, dM22 );
962         ImplWriteDouble( &pTemp, nX - ( dM11 * nBoundingBox[0] ) );
963         ImplWriteDouble( &pTemp, mnHeight - nY - ( dM22 * nBoundingBox[3] ) );
964         ImplWriteString( &pTemp, "] concat /showpage {} def\n" );
965 
966         if ( DevEscape( mhDC, DEVESC_RAWDATA, pTemp - pBuf,
967             (PBYTE)pBuf, 0, NULL ) == DEV_OK )
968 #endif //
969         {
970             UINT32 nToDo = nSize;
971             UINT32 nDoNow;
972             bRet = TRUE;
973             while( nToDo && bRet )
974             {
975                 nDoNow = 0x4000;
976                 if ( nToDo < nDoNow )
977                     nDoNow = nToDo;
978 
979                 if ( DevEscape( mhDC, DEVESC_RAWDATA, nDoNow, (PBYTE)pPtr + nSize - nToDo,
980                    0, NULL ) == -1 )
981                     bRet = FALSE;
982                 nToDo -= nDoNow;
983             }
984 
985             if ( bRet )
986             {
987                 strcpy ( (char*)pBuf, "\nrestore\n" );
988                 if ( DevEscape( mhDC, DEVESC_RAWDATA, 9, (PBYTE)pBuf,
989                     0, NULL ) == DEV_OK ) bRet = TRUE;
990             }
991 
992                 // #107797# Write out EPS encapsulation footer
993                 // ----------------------------------------------------------------------------------
994                 // reserve a USHORT again
995                 aBuf.setLength( 2 );
996                 aBuf.append( "%%EndDocument\n"
997                              "count op_count_salWin sub {pop} repeat\n"
998                              "countdictstack dict_count_salWin sub {end} repeat\n"
999                              "b4_Inc_state_salWin restore\n\n" );
1000                 *((USHORT*)aBuf.getStr()) = (USHORT)( aBuf.getLength() - 2 );
1001                 DevEscape( mhDC, DEVESC_RAWDATA, aBuf.getLength(),
1002                         (PBYTE)aBuf.getStr(), 0, NULL );
1003                 bRet = TRUE;
1004 
1005         }
1006     }
1007     delete [] pBuf;
1008     return bRet;
1009 }
1010 
1011 /*
1012  * IsNativeControlSupported()
1013  *
1014  *  Returns TRUE if the platform supports native
1015  *  drawing of the control defined by nPart
1016  */
1017 BOOL Os2SalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
1018 {
1019     return( FALSE );
1020 }
1021 
1022 // -----------------------------------------------------------------------
1023 
1024 SystemGraphicsData Os2SalGraphics::GetGraphicsData() const
1025 {
1026     SystemGraphicsData aRes;
1027     aRes.nSize = sizeof(aRes);
1028 #if 0
1029     aRes.hDC = mhDC;
1030 #endif
1031     return aRes;
1032 }
1033 
1034 // -----------------------------------------------------------------------
1035