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