xref: /aoo41x/main/vcl/os2/source/gdi/salgdi.cxx (revision fc9fd3f1)
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