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