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