1 /*
2 		stock.c
3 
4 		Stock objects - pens, brushes, fonts
5 */
6 
7 #include "win32\win32guts.h"
8 #ifndef _APRICOT_H_
9 #include "apricot.h"
10 #endif
11 #include "guts.h"
12 #include <ctype.h>
13 #include "Window.h"
14 #include "Image.h"
15 #include "Printer.h"
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 
22 #define  sys (( PDrawableData)(( PComponent) self)-> sysData)->
23 #define  dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
24 #define var (( PWidget) self)->
25 #define HANDLE sys handle
26 #define DHANDLE(x) dsys(x) handle
27 
28 // Stylus section
29 PDCStylus
stylus_alloc(PStylus data)30 stylus_alloc( PStylus data)
31 {
32 	Bool extPen = data-> extPen. actual;
33 	PDCStylus ret = ( PDCStylus) hash_fetch( stylusMan, data, sizeof( Stylus) - ( extPen ? 0 : sizeof( EXTPEN)));
34 	if ( ret == NULL) {
35 		LOGPEN p;
36 		LOGBRUSH * b;
37 		LOGBRUSH   xbrush;
38 
39 		if ( hash_count( stylusMan) > 128)
40 			stylus_clean();
41 
42 		ret = ( PDCStylus) malloc( sizeof( DCStylus));
43 		if ( !ret) return NULL;
44 
45 		memcpy( &ret-> s, data, sizeof( Stylus));
46 		ret-> refcnt = 0;
47 		p = ret-> s. pen;
48 
49 		if ( !extPen) {
50 			if ( !( ret-> hpen = CreatePenIndirect( &p))) {
51 				apiErr;
52 				ret-> hpen = CreatePen( PS_SOLID, 0, 0);
53 			}
54 		} else {
55 			int i, delta = p. lopnWidth. x > 1 ? p. lopnWidth. x - 1 : 0;
56 			LOGBRUSH pb;
57 			pb. lbStyle = BS_SOLID;
58 			pb. lbColor = ret-> s. pen. lopnColor;
59 			pb. lbHatch = 0;
60 			for ( i = 1; i < ret-> s. extPen. patResource-> dotsCount; i += 2)
61 				ret-> s. extPen. patResource-> dotsPtr[ i] += delta;
62 			if ( !( ret-> hpen   = ExtCreatePen( ret-> s. extPen. style, p. lopnWidth. x, &pb,
63 				ret-> s. extPen. patResource-> dotsCount,
64 				ret-> s. extPen. patResource-> dotsPtr
65 			))) {
66 				apiErr;
67 				ret-> hpen = CreatePen( PS_SOLID, 0, 0);
68 			}
69 			for ( i = 1; i < ret-> s. extPen. patResource-> dotsCount; i += 2)
70 				ret-> s. extPen. patResource-> dotsPtr[ i] -= delta;
71 		}
72 		b = &ret-> s. brush. lb;
73 		if ( ret-> s. brush. lb. lbStyle == BS_DIBPATTERNPT) {
74 			if ( ret-> s. brush. backColor == ret-> s. pen. lopnColor) {
75 				// workaround Win32 bug with mono bitmaps -
76 				// if color and backColor are the same, but fill pattern present, backColor
77 				// value is ignored by some unknown, but certainly important reason :)
78 				xbrush. lbStyle = BS_SOLID;
79 				xbrush. lbColor = ret-> s. pen. lopnColor;
80 				xbrush. lbHatch = 0;
81 				b = &xbrush;
82 			} else {
83 				int i;
84 				for ( i = 0; i < 8; i++) bmiHatch. bmiData[ i * 4] = ret-> s. brush. pattern[ i];
85 				bmiHatch. bmiColors[ 0]. rgbRed   =  ( ret-> s. brush. backColor & 0xFF);
86 				bmiHatch. bmiColors[ 0]. rgbGreen = (( ret-> s. brush. backColor >> 8) & 0xFF);
87 				bmiHatch. bmiColors[ 0]. rgbBlue  = (( ret-> s. brush. backColor >> 16) & 0xFF);
88 				bmiHatch. bmiColors[ 1]. rgbRed   =  ( ret-> s. pen. lopnColor & 0xFF);
89 				bmiHatch. bmiColors[ 1]. rgbGreen = (( ret-> s. pen. lopnColor >> 8) & 0xFF);
90 				bmiHatch. bmiColors[ 1]. rgbBlue  = (( ret-> s. pen. lopnColor >> 16) & 0xFF);
91 			}
92 		}
93 		if ( !( ret-> hbrush = CreateBrushIndirect( b))) {
94 			apiErr;
95 			ret-> hbrush = CreateSolidBrush( RGB( 255, 255, 255));
96 		}
97 		hash_store( stylusMan, &ret-> s, sizeof( Stylus) - ( data-> extPen. actual ? 0 : sizeof( EXTPEN)), ret);
98 	}
99 	ret-> refcnt++;
100 	return ret;
101 }
102 
103 void
stylus_free(PDCStylus res,Bool permanent)104 stylus_free( PDCStylus res, Bool permanent)
105 {
106 	if ( !res || --res-> refcnt > 0) return;
107 	if ( !permanent) {
108 		res-> refcnt = 0;
109 		return;
110 	}
111 	if ( res-> hpen)   DeleteObject( res-> hpen);
112 	if ( res-> hbrush) DeleteObject( res-> hbrush);
113 	res-> hbrush = NULL;
114 	res-> hpen = NULL;
115 	hash_delete( stylusMan, &res-> s, sizeof( Stylus) - ( res-> s. extPen. actual ? 0 : sizeof( EXTPEN)), true);
116 }
117 
_st_cleaner(PDCStylus s,int keyLen,void * key,void * dummy)118 static Bool _st_cleaner( PDCStylus s, int keyLen, void * key, void * dummy) {
119 	if ( s-> refcnt <= 0) stylus_free( s, true);
120 	return false;
121 }
122 
123 void
stylus_clean()124 stylus_clean()
125 {
126 	hash_first_that( stylusMan, _st_cleaner, NULL, NULL, NULL);
127 }
128 
129 Bool
stylus_extpenned(PStylus s)130 stylus_extpenned( PStylus s)
131 {
132 	if ( s-> pen. lopnWidth. x > 1) {
133 		if ( s-> pen. lopnStyle == PS_NULL)
134 			return false;
135 		return true;
136 	} else if ( s-> pen. lopnStyle == PS_USERSTYLE)
137 		return true;
138 	return false;
139 }
140 
141 Bool
stylus_complex(PStylus s,HDC dc)142 stylus_complex( PStylus s, HDC dc)
143 {
144 	int rop;
145 	if ( s-> brush. lb. lbStyle == BS_DIBPATTERNPT)
146 		return true;
147 	if (( s-> pen. lopnStyle != PS_SOLID) &&
148 		( s-> pen. lopnStyle != PS_NULL))
149 		return true;
150 	rop = GetROP2( dc);
151 	if (( rop != R2_COPYPEN) &&
152 		( rop != R2_WHITE  ) &&
153 		( rop != R2_NOP    ) &&
154 		( rop != R2_BLACK  )) return true;
155 	return false;
156 }
157 
158 
159 DWORD
stylus_get_extpen_style(PStylus s)160 stylus_get_extpen_style( PStylus s)
161 {
162 	return s-> extPen. lineEnd | s-> pen. lopnStyle | s-> extPen. lineJoin | PS_GEOMETRIC;
163 }
164 
165 void
stylus_gp_free(PDCGPStylus res,Bool permanent)166 stylus_gp_free( PDCGPStylus res, Bool permanent)
167 {
168 	if ( !res || --res-> refcnt > 0) return;
169 	if ( !permanent) {
170 		res-> refcnt = 0;
171 		return;
172 	}
173 	if ( res-> brush) GdipDeleteBrush( res-> brush);
174 	res-> brush = NULL;
175 	if ( res-> pen ) GdipDeletePen(res-> pen);
176 	res-> pen = NULL;
177 	hash_delete( stylusGpMan, &res-> s, sizeof( GPStylus), true);
178 }
179 
_gp_cleaner(PDCGPStylus s,int keyLen,void * key,void * dummy)180 static Bool _gp_cleaner( PDCGPStylus s, int keyLen, void * key, void * dummy) {
181 	if ( s-> refcnt <= 0) stylus_gp_free( s, true);
182 	return false;
183 }
184 
185 void
stylus_gp_clean()186 stylus_gp_clean()
187 {
188 	hash_first_that( stylusGpMan, _gp_cleaner, nil, nil, nil);
189 }
190 
191 static PDCGPStylus
stylus_gp_fetch(GPStylus * key)192 stylus_gp_fetch( GPStylus * key)
193 {
194 	PDCGPStylus cached;
195 
196 	cached = ( PDCGPStylus) hash_fetch( stylusGpMan, key, sizeof(GPStylus));
197 
198 	if ( cached == NULL ) {
199 		if (( cached = malloc(sizeof(DCGPStylus))) == NULL) {
200 			warn("Not enough memory");
201 			return NULL;
202 		}
203 		memset( cached, 0, sizeof(DCGPStylus));
204 		cached->s = *key;
205 		if ( hash_count( stylusGpMan) > 128)
206 			stylus_gp_clean();
207 		hash_store( stylusGpMan, key, sizeof(GPStylus), cached);
208 	}
209 
210 	return cached;
211 }
212 
213 GpBrush*
stylus_gp_alloc(Handle self)214 stylus_gp_alloc(Handle self)
215 {
216 	GPStylus key;
217 	DCGPStylus *cached;
218 	int r,g,b;
219 	PStylus s = & sys stylus;
220 
221 	if ( sys stylusGPResource) {
222 		stylus_gp_free( sys stylusGPResource, 0);
223 		sys stylusGPResource = NULL;
224 	}
225 
226 	memset(&key, 0, sizeof(key));
227 
228 	b = (s->pen.lopnColor >> 16) & 0xff;
229 	g = (s->pen.lopnColor & 0xff00) >> 8;
230 	r = s->pen.lopnColor & 0xff;
231 	key.fg = (sys alpha << 24) | (r << 16) | (g << 8) | b;
232 	if ( s-> brush. lb. lbStyle != BS_SOLID ) {
233 		key.opaque = (sys currentROP2 == ropCopyPut) ? 1 : 0;
234 		b = (s->brush.backColor >> 16) & 0xff;
235 		g = (s->brush.backColor & 0xff00) >> 8;
236 		r = s->brush.backColor & 0xff;
237 		key.bg = (sys alpha << 24) | (r << 16) | (g << 8) | b;
238 		*key.fill = *sys fillPattern;
239 	}
240 
241 	if ((cached = stylus_gp_fetch(&key)) == NULL)
242 		return NULL;
243 
244 	if ( cached->brush == NULL ) {
245 		if ( s-> brush. lb. lbStyle == BS_SOLID ) {
246 			GpSolidFill *f;
247 			GPCALL GdipCreateSolidFill((ARGB)key.fg, &f);
248 			if ( rc ) goto FAIL;
249 
250 			cached->brush = (GpBrush*)f;
251 		} else {
252 			GpBitmap * b;
253 			GpTexture * t;
254 			uint32_t x, y, fp[64], *fpp, bg;
255 
256 			bg = key.opaque ? key.bg : 0x00000000;
257 			for ( y = 0, fpp = fp; y < 8; y++) {
258 				Byte src = sys fillPattern[y];
259 				for ( x = 0; x < 8; x++)
260 					*(fpp++) = (src & ( 1 << x )) ? key.fg : bg;
261 			}
262 
263 			GPCALL GdipCreateBitmapFromScan0( 8, 8, 32, PixelFormat32bppARGB, (BYTE*)fp, &b);
264 			apiGPErrCheck;
265 			if ( rc ) goto FAIL;
266 
267 			GPCALL GdipCreateTexture((GpImage*) b, WrapModeTile, &t);
268 			apiGPErrCheck;
269 			GdipDisposeImage((GpImage*) b);
270 			if ( rc ) goto FAIL;
271 
272 			cached->brush = (GpBrush*) t;
273 		}
274 	}
275 
276 	cached-> refcnt++;
277 	sys stylusGPResource = cached;
278 	return cached;
279 
280 FAIL:
281 	hash_delete( stylusGpMan, &key, sizeof(key), true);
282 	return NULL;
283 }
284 
285 void
stylus_change(Handle self)286 stylus_change( Handle self)
287 {
288 	PDCStylus p;
289 	PDCStylus newP;
290 
291 	if ( is_apt( aptDCChangeLock)) return;
292 	sys stylusFlags &= ~stbGPBrush;
293 
294 	p    = sys stylusResource;
295 	newP = stylus_alloc( &sys stylus);
296 	if ( p != newP) {
297 		sys stylusResource = newP;
298 		sys stylusFlags &= stbGPBrush;
299 	}
300 	stylus_free( p, false);
301 }
302 
303 GpPen*
stylus_gp_get_pen(int lineWidth,uint32_t color)304 stylus_gp_get_pen(int lineWidth, uint32_t color)
305 {
306 	GPStylus key;
307 	PDCGPStylus cached;
308 
309 	memset( &key, 0, sizeof(key));
310 	key.type   = GP_SOLID_PEN;
311 	key.fg     = color;
312 	key.opaque = lineWidth;
313 	if (( cached = stylus_gp_fetch(&key)) == NULL)
314 		return NULL;
315 
316 	if ( cached->pen == NULL ) {
317 		GPCALL GdipCreatePen1(color, lineWidth, UnitPixel, &cached->pen);
318 		apiGPErrCheck;
319 		if ( rc ) goto FAIL;
320 	}
321 
322 	return cached->pen;
323 
324 FAIL:
325 	hash_delete( stylusGpMan, &key, sizeof(key), true);
326 	return NULL;
327 }
328 
329 PPatResource
patres_fetch(unsigned char * pattern,int len)330 patres_fetch( unsigned char * pattern, int len)
331 {
332 	int i;
333 	PPatResource r = ( PPatResource) hash_fetch( patMan, pattern, len);
334 	if ( r)
335 		return r;
336 
337 	r = ( PPatResource) malloc( sizeof( PatResource) + sizeof( DWORD) * len);
338 	if ( !r) return &hPatHollow;
339 
340 	r-> dotsCount = len;
341 	r-> dotsPtr   = r-> dots;
342 	for ( i = 0; i < len; i++) {
343 		DWORD x = ( DWORD) pattern[ i];
344 		if ( i & 1)
345 			x++;
346 		else
347 			if ( x > 0) x--;
348 		r-> dots[ i] = x;
349 	}
350 	hash_store( patMan, pattern, len, r);
351 	return r;
352 }
353 
354 UINT
patres_user(unsigned char * pattern,int len)355 patres_user( unsigned char * pattern, int len)
356 {
357 	switch ( len) {
358 	case 0:
359 		return PS_NULL;
360 	case 1:
361 		return pattern[0] ? PS_SOLID : PS_NULL;
362 	default:
363 		return PS_USERSTYLE;
364 	}
365 }
366 
367 // Stylus end
368 
369 // Font section
370 
371 
372 #define FONTHASH_SIZE 563
373 #define FONTIDHASH_SIZE 23
374 
375 typedef struct _FontHashNode
376 {
377 	struct _FontHashNode *next;
378 	struct _FontHashNode *next2;
379 	Font key;
380 	Font value;
381 } FontHashNode, *PFontHashNode;
382 
383 typedef struct _FontHash
384 {
385 	PFontHashNode buckets[ FONTHASH_SIZE];
386 } FontHash, *PFontHash;
387 
388 static FontHash fontHash;
389 static FontHash fontHashBySize;
390 
391 static unsigned long
elf_hash(const char * key,int size,unsigned long h)392 elf_hash( const char *key, int size, unsigned long h)
393 {
394 	unsigned long g;
395 	if ( size >= 0) {
396 		while ( size) {
397 			h = ( h << 4) + *key++;
398 			if (( g = h & 0xF0000000))
399 				h ^= g >> 24;
400 			h &= ~g;
401 			size--;
402 		}
403 	} else {
404 		while ( *key) {
405 			h = ( h << 4) + *key++;
406 			if (( g = h & 0xF0000000))
407 				h ^= g >> 24;
408 			h &= ~g;
409 		}
410 	}
411 	return h;
412 }
413 
414 static unsigned long
elf(Font * font,Bool bySize)415 elf( Font * font, Bool bySize)
416 {
417 	unsigned long seed = 0;
418 	if ( bySize) {
419 		seed = elf_hash( (const char*)&font-> width, (char *)(&(font-> name)) - (char *)&(font-> width), seed);
420 		seed = elf_hash( font-> name, -1, seed);
421 		seed = elf_hash( font-> encoding, -1, seed);
422 		seed = elf_hash( (const char*)&font-> size, sizeof( font-> size), seed);
423 	} else {
424 		seed = elf_hash( (const char*)&font-> height, (char *)(&(font-> name)) - (char *)&(font-> height), seed);
425 		seed = elf_hash( font-> name, -1, seed);
426 		seed = elf_hash( font-> encoding, -1, seed);
427 	}
428 	return seed % FONTHASH_SIZE;
429 }
430 
431 
432 static PFontHashNode
find_node(const PFont font,Bool bySize)433 find_node( const PFont font, Bool bySize)
434 {
435 	unsigned long i;
436 	PFontHashNode node;
437 	int sz;
438 
439 	if ( font == NULL) return NULL;
440 
441 	i = elf( font, bySize);
442 	if (bySize)
443 		node = fontHashBySize. buckets[ i];
444 	else
445 		node = fontHash. buckets[ i];
446 	if ( bySize) {
447 		sz = (char *)(&(font-> name)) - (char *)&(font-> width);
448 		while ( node != NULL)
449 		{
450 			if (( memcmp( &(font-> width), &(node-> key. width), sz) == 0) &&
451 				( strcmp( font-> name, node-> key. name) == 0 ) &&
452 				( strcmp( font-> encoding, node-> key. encoding) == 0 ) &&
453 				(font-> resolution == node-> key. resolution) &&
454 				(font-> size == node-> key. size))
455 				return node;
456 			node = node-> next2;
457 		}
458 	} else {
459 		sz = (char *)(&(font-> name)) - (char *)&(font-> height);
460 		while ( node != NULL)
461 		{
462 			if (( memcmp( font, &(node-> key), sz) == 0) &&
463 				( strcmp( font-> name, node-> key. name) == 0 )&&
464 				(font-> resolution == node-> key. resolution) &&
465 				( strcmp( font-> encoding, node-> key. encoding) == 0 ))
466 				return node;
467 			node = node-> next;
468 		}
469 	}
470 	return NULL;
471 }
472 
473 Bool
add_font_to_hash(const PFont key,const PFont font,Bool addSizeEntry)474 add_font_to_hash( const PFont key, const PFont font, Bool addSizeEntry)
475 {
476 	PFontHashNode node;
477 	unsigned long i;
478 
479 	node = ( PFontHashNode) malloc( sizeof( FontHashNode));
480 	if ( node == NULL) return false;
481 	memcpy( &(node-> key), key, sizeof( Font));
482 	memcpy( &(node-> value), font, sizeof( Font));
483 	i = elf(key, 0);
484 	node-> next = fontHash. buckets[ i];
485 	fontHash. buckets[ i] = node;
486 	if ( addSizeEntry) {
487 		i = elf( key, 1);
488 		node-> next2 = fontHashBySize. buckets[ i];
489 		fontHashBySize. buckets[ i] = node;
490 	}
491 	return true;
492 }
493 
494 Bool
get_font_from_hash(PFont font,Bool bySize)495 get_font_from_hash( PFont font, Bool bySize)
496 {
497 	PFontHashNode node = find_node( font, bySize);
498 	if ( node == NULL) return false;
499 	*font = node-> value;
500 	return true;
501 }
502 
503 Bool
create_font_hash(void)504 create_font_hash( void)
505 {
506 	memset ( &fontHash, 0, sizeof( FontHash));
507 	memset ( &fontHashBySize, 0, sizeof( FontHash));
508 	return true;
509 }
510 
511 Bool
destroy_font_hash(void)512 destroy_font_hash( void)
513 {
514 	PFontHashNode node, node2;
515 	int i;
516 	for ( i = 0; i < FONTHASH_SIZE; i++)
517 	{
518 		node = fontHash. buckets[ i];
519 		while ( node)
520 		{
521 			node2 = node;
522 			node = node-> next;
523 			free( node2);
524 		}
525 	}
526 	create_font_hash();     // just in case...
527 	return true;
528 }
529 
530 
_ft_cleaner(PDCFont f,int keyLen,void * key,void * dummy)531 static Bool _ft_cleaner( PDCFont f, int keyLen, void * key, void * dummy) {
532 	if ( f-> refcnt <= 0) font_free( f, true);
533 	return false;
534 }
535 
536 static int
build_dcfont_key(Font * src,unsigned char * key)537 build_dcfont_key( Font * src, unsigned char * key)
538 {
539 	int sz = FONTSTRUCSIZE;
540 	char * p;
541 	memcpy( key, src, FONTSTRUCSIZE);
542 	key += FONTSTRUCSIZE;
543 	p = src-> name;
544 	while ( *p) {
545 		*(key++) = *(p++);
546 		sz++;
547 	}
548 	*(key++) = 0;
549 	sz++;
550 	p = src-> encoding;
551 	while ( *p) {
552 		*(key++) = *(p++);
553 		sz++;
554 	}
555 	*(key++) = 0;
556 	sz++;
557 	return sz;
558 }
559 
560 PDCFont
font_alloc(Font * data)561 font_alloc( Font * data)
562 {
563 	char key[sizeof(Font)];
564 	int keyLen = build_dcfont_key( data, (unsigned char*)key);
565 	PDCFont ret = ( PDCFont) hash_fetch( fontMan, key, keyLen);
566 
567 	if ( ret == NULL) {
568 		LOGFONTW logfont;
569 		PFont   f;
570 
571 		if ( hash_count( fontMan) > 128)
572 			font_clean();
573 
574 		ret = ( PDCFont) malloc( sizeof( DCFont));
575 		if ( !ret) return NULL;
576 
577 		memcpy( f = &ret-> font, data, sizeof( Font));
578 		ret-> refcnt = 0;
579 		font_font2logfont( f, &logfont);
580 		if ( !( ret-> hfont  = CreateFontIndirectW( &logfont))) {
581 			LOGFONTW lf;
582 			apiErr;
583 			memset( &lf, 0, sizeof( lf));
584 			ret-> hfont = CreateFontIndirectW( &lf);
585 		}
586 		keyLen = build_dcfont_key( &ret-> font, (unsigned char*)key);
587 		hash_store( fontMan, key, keyLen, ret);
588 	}
589 	ret-> refcnt++;
590 	return ret;
591 }
592 
593 void
font_free(PDCFont res,Bool permanent)594 font_free( PDCFont res, Bool permanent)
595 {
596 	int keyLen;
597 	char key[sizeof(Font)];
598 
599 	if ( !res || --res-> refcnt > 0) return;
600 	if ( !permanent) {
601 		res-> refcnt = 0;
602 		return;
603 	}
604 	if ( res-> hfont) {
605 		DeleteObject( res-> hfont);
606 		res-> hfont = NULL;
607 	}
608 	keyLen = build_dcfont_key( &res-> font, (unsigned char*)key);
609 	hash_delete( fontMan, key, keyLen, true);
610 }
611 
612 void
font_change(Handle self,Font * font)613 font_change( Handle self, Font * font)
614 {
615 	PDCFont p;
616 	PDCFont newP;
617 	if ( is_apt( aptDCChangeLock)) return;
618 
619 	sys alphaArenaFontChanged = true;
620 	p    = sys fontResource;
621 	newP = ( sys fontResource = font_alloc( font));
622 	if ( sys alphaArenaStockFont ) {
623 		SelectObject( sys alphaArenaDC, sys alphaArenaStockFont );
624 		sys alphaArenaFontChanged = true;
625 	}
626 	font_free( p, false);
627 	if ( sys ps)
628 		SelectObject( sys ps, newP-> hfont);
629 }
630 
631 void
font_clean()632 font_clean()
633 {
634 	hash_first_that( fontMan, _ft_cleaner, NULL, NULL, NULL);
635 }
636 
637 static char* encodings[] = {
638 	"Western",
639 	"Windows",
640 	"Symbol",
641 	"Shift-JIS",
642 	"Hangeul",
643 	"GB 2312",
644 	"Chinese Big 5",
645 	"OEM DOS",
646 	"Johab",
647 	"Hebrew",
648 	"Arabic",
649 	"Greek",
650 	"Turkish",
651 	"Vietnamese",
652 	"Thai",
653 	"Eastern Europe",
654 	"Cyrillic",
655 	"Mac",
656 	"Baltic",
657 	NULL
658 };
659 
660 static Handle ctx_CHARSET2index[] = {
661 	ANSI_CHARSET        , 0,
662 	DEFAULT_CHARSET     , 1,
663 	SYMBOL_CHARSET      , 2,
664 	SHIFTJIS_CHARSET    , 3,
665 	HANGEUL_CHARSET     , 4,
666 	GB2312_CHARSET      , 5,
667 	CHINESEBIG5_CHARSET , 6,
668 	OEM_CHARSET         , 7,
669 #ifdef JOHAB_CHARSET
670 	JOHAB_CHARSET       , 8,
671 	HEBREW_CHARSET      , 9,
672 	ARABIC_CHARSET      , 10,
673 	GREEK_CHARSET       , 11,
674 	TURKISH_CHARSET     , 12,
675 	VIETNAMESE_CHARSET  , 13,
676 	THAI_CHARSET        , 14,
677 	EASTEUROPE_CHARSET  , 15,
678 	RUSSIAN_CHARSET     , 16,
679 	MAC_CHARSET         , 17,
680 	BALTIC_CHARSET      , 18,
681 #endif
682 	endCtx
683 };
684 
685 #define MASK_CODEPAGE  0x00FF
686 #define MASK_FAMILY    0xFF00
687 #define FF_MASK        0x00F0
688 
689 static char *
font_charset2encoding(int charset)690 font_charset2encoding( int charset)
691 {
692 #define SYNCPLEN 7
693 	static char buf[ SYNCPLEN * 256], initialized = false;
694 	char *str;
695 	int index = ctx_remap_end( charset, ctx_CHARSET2index, true);
696 	if ( index == endCtx) {
697 		charset &= 255;
698 		if ( !initialized) {
699 			int i;
700 			for ( i = 0; i < 256; i++) sprintf( buf + i * SYNCPLEN, "CP-%d", i);
701 			initialized = true;
702 		}
703 		str = buf + charset * SYNCPLEN;
704 	} else
705 		str = encodings[ index];
706 	return str;
707 }
708 
709 static int
font_encoding2charset(const char * encoding)710 font_encoding2charset( const char * encoding)
711 {
712 	int index = 0;
713 	char ** e = encodings;
714 
715 	if ( !encoding || encoding[0] == 0) return DEFAULT_CHARSET;
716 
717 	while ( *e) {
718 		if ( strcmp( *e, encoding) == 0)
719 			return ctx_remap_def( index, ctx_CHARSET2index, false, DEFAULT_CHARSET);
720 		index++;
721 		e++;
722 	}
723 	if ( strncmp( encoding, "CP-", 3) == 0) {
724 		int i = atoi( encoding + 3);
725 		if ( i <= 0 || i > 256) i = DEFAULT_CHARSET;
726 		return i;
727 	}
728 	return DEFAULT_CHARSET;
729 }
730 
731 static Bool
utf8_flag_strncpy(char * dst,const WCHAR * src,unsigned int maxlen)732 utf8_flag_strncpy( char * dst, const WCHAR * src, unsigned int maxlen)
733 {
734 	int i;
735 	Bool is_utf8 = false;
736 	for ( i = 0; i < maxlen && src[i] > 0; i++) {
737 		if ( src[i] > 0x7f ) {
738 			is_utf8 = true;
739 			break;
740 		}
741 	}
742 	WideCharToMultiByte(CP_UTF8, 0, src, -1, (LPSTR)dst, 256, NULL, false);
743 	return is_utf8;
744 }
745 
746 int CALLBACK
fep_register_mapper_fonts(ENUMLOGFONTEXW FAR * e,NEWTEXTMETRICEXW FAR * t,DWORD type,LPARAM _es)747 fep_register_mapper_fonts( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICEXW FAR *t, DWORD type, LPARAM _es)
748 {
749 	char name[LF_FACESIZE + 1];
750 	Bool name_is_utf8;
751 	unsigned int i, styles[4], pitch;
752 	if (type & RASTER_FONTTYPE) return 1;
753 
754 	if (e-> elfLogFont.lfFaceName[0] == '@') return 1; /* vertical font */
755 
756 	name_is_utf8 = utf8_flag_strncpy( name, e-> elfLogFont.lfFaceName, LF_FACESIZE);
757 	pitch =
758 		((( e-> elfLogFont.lfPitchAndFamily & 3) == DEFAULT_PITCH ) ? fpDefault :
759 		((( e-> elfLogFont.lfPitchAndFamily & 3) == VARIABLE_PITCH) ? fpVariable : fpFixed));
760 
761 	styles[0] = fsNormal;
762 	styles[1] = fsBold;
763 	styles[2] = fsItalic;
764 	styles[3] = fsBold | fsItalic;
765 	for ( i = 0; i < 4; i++) {
766 		PFont f;
767 
768 		if ((f = prima_font_mapper_save_font(name, styles[i])) == NULL)
769 			continue;
770 
771 		f->undef.pitch    = 0;
772 		f->pitch          = pitch;
773 		f->undef.vector   = 0;
774 		f->vector         = fvOutline;
775 		f->is_utf8.name   = name_is_utf8;
776 		f->is_utf8.family = utf8_flag_strncpy( f-> family, e-> elfFullName, LF_FULLFACESIZE);
777 	}
778 	return 1;
779 }
780 
781 void
register_mapper_fonts(void)782 register_mapper_fonts(void)
783 {
784 	HDC dc;
785 	LOGFONTW elf;
786 
787 	/* MS Shell Dlg is a virtual font, not reported by enum */
788 	prima_font_mapper_save_font(guts.windowFont.name, 0);
789 
790 	if ( !( dc = dc_alloc()))
791 		return;
792 	memset( &elf, 0, sizeof( elf));
793 	elf. lfCharSet = DEFAULT_CHARSET;
794 	EnumFontFamiliesExW( dc, &elf, (FONTENUMPROCW) fep_register_mapper_fonts, 0, 0);
795 	dc_free();
796 }
797 
798 void
reset_system_fonts(void)799 reset_system_fonts(void)
800 {
801 	memset( &guts. windowFont, 0, sizeof( Font));
802 	strcpy( guts. windowFont. name, DEFAULT_WIDGET_FONT);
803 	guts. windowFont. size  = DEFAULT_WIDGET_FONT_SIZE;
804 	guts. windowFont. undef. width = guts. windowFont. undef. height = guts. windowFont. undef. vector = 1;
805 	apc_font_pick( NULL_HANDLE, &guts. windowFont, &guts. windowFont);
806 
807 	guts. ncmData. cbSize = sizeof( NONCLIENTMETRICSW);
808 	if ( !SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( NONCLIENTMETRICSW),
809 		( PVOID) &guts. ncmData, 0)) apiErr;
810 	font_logfont2font( &guts.ncmData.lfMenuFont,    &guts.menuFont, &guts.displayResolution);
811 	font_logfont2font( &guts.ncmData.lfMessageFont, &guts.msgFont,  &guts.displayResolution);
812 	font_logfont2font( &guts.ncmData.lfCaptionFont, &guts.capFont,  &guts.displayResolution);
813 }
814 
815 void
font_logfont2font(LOGFONTW * lf,Font * f,Point * res)816 font_logfont2font( LOGFONTW * lf, Font * f, Point * res)
817 {
818 	TEXTMETRICW tm;
819 	HDC dc = dc_alloc();
820 	HFONT hf;
821 
822 	if ( !dc) return;
823 	hf = SelectObject( dc, CreateFontIndirectW( lf));
824 
825 	GetTextMetricsW( dc, &tm);
826 	DeleteObject( SelectObject( dc, hf));
827 	dc_free();
828 
829 	if ( !res) res = &guts. displayResolution;
830 	bzero( f, sizeof(Font));
831 	f-> height              = tm. tmHeight;
832 	f-> size                = ( f-> height - tm. tmInternalLeading) * 72.0 / res-> y + 0.5;
833 	f-> width               = lf-> lfWidth;
834 	f-> direction           = (double)(lf-> lfEscapement) / 10.0;
835 	f-> vector              = (( tm. tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE)) ? fvOutline : fvBitmap);
836 	f-> style               = 0 |
837 		( lf-> lfItalic     ? fsItalic     : 0) |
838 		( lf-> lfUnderline  ? fsUnderlined : 0) |
839 		( lf-> lfStrikeOut  ? fsStruckOut  : 0) |
840 		(( lf-> lfWeight >= 700) ? fsBold   : 0);
841 	f-> pitch               = ((( lf-> lfPitchAndFamily & 3) == DEFAULT_PITCH) ? fpDefault :
842 		((( lf-> lfPitchAndFamily & 3) == VARIABLE_PITCH) ? fpVariable : fpFixed));
843 	strcpy( f-> encoding, font_charset2encoding( lf-> lfCharSet));
844 	f-> is_utf8.name = utf8_flag_strncpy( f->name, lf->lfFaceName, LF_FACESIZE);
845 }
846 
847 void
font_font2logfont(Font * f,LOGFONTW * lf)848 font_font2logfont( Font * f, LOGFONTW * lf)
849 {
850 	lf-> lfHeight           = f-> height;
851 	lf-> lfWidth            = f-> width;
852 	lf-> lfEscapement       = f-> direction * 10;
853 	lf-> lfOrientation      = f-> direction * 10;
854 	lf-> lfWeight           = ( f-> style & fsBold)       ? 800 : 400;
855 	lf-> lfItalic           = ( f-> style & fsItalic)     ? 1 : 0;
856 	lf-> lfUnderline        = 0;
857 	lf-> lfStrikeOut        = 0;
858 	lf-> lfOutPrecision     = f-> vector ? OUT_TT_PRECIS : OUT_RASTER_PRECIS;
859 	lf-> lfClipPrecision    = CLIP_DEFAULT_PRECIS;
860 	lf-> lfQuality          = PROOF_QUALITY;
861 	lf-> lfPitchAndFamily   = FF_DONTCARE;
862 	lf-> lfCharSet          = font_encoding2charset( f-> encoding);
863 	MultiByteToWideChar(CP_UTF8, 0, f->name, -1, lf->lfFaceName, LF_FACESIZE);
864 }
865 
866 void
font_textmetric2font(TEXTMETRICW * tm,Font * fm,Bool readonly)867 font_textmetric2font( TEXTMETRICW * tm, Font * fm, Bool readonly)
868 {
869 	if ( !readonly) {
870 		fm-> size            = ( tm-> tmHeight - tm-> tmInternalLeading) * 72.0 / guts. displayResolution.y + 0.5;
871 		fm-> width           = tm-> tmAveCharWidth;
872 		fm-> height          = tm-> tmHeight;
873 		fm-> style           = 0 |
874 			( tm-> tmItalic     ? fsItalic     : 0) |
875 			( tm-> tmUnderlined ? fsUnderlined : 0) |
876 			( tm-> tmStruckOut  ? fsStruckOut  : 0) |
877 			(( tm-> tmWeight >= 700) ? fsBold   : 0)
878 			;
879 	}
880 	fm-> pitch  = (( tm-> tmPitchAndFamily & TMPF_FIXED_PITCH) ? fpVariable : fpFixed);
881 	fm-> vector = (( tm-> tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE)) ? true : false);
882 	fm-> weight                 = tm-> tmWeight / 100;
883 	fm-> ascent                 = tm-> tmAscent;
884 	fm-> descent                = tm-> tmDescent;
885 	fm-> maximalWidth           = tm-> tmMaxCharWidth;
886 	fm-> internalLeading        = tm-> tmInternalLeading;
887 	fm-> externalLeading        = tm-> tmExternalLeading;
888 	fm-> xDeviceRes             = tm-> tmDigitizedAspectX;
889 	fm-> yDeviceRes             = tm-> tmDigitizedAspectY;
890 	fm-> firstChar              = tm-> tmFirstChar;
891 	fm-> lastChar               = tm-> tmLastChar;
892 	fm-> breakChar              = tm-> tmBreakChar;
893 	fm-> defaultChar            = tm-> tmDefaultChar;
894 	strcpy( fm-> encoding, font_charset2encoding( tm-> tmCharSet));
895 }
896 
897 void
font_pp2font(char * presParam,Font * f)898 font_pp2font( char * presParam, Font * f)
899 {
900 	int i;
901 	char * p = strchr( presParam, '.');
902 
903 	memset( f, 0, sizeof( Font));
904 	if ( p) {
905 		f-> size = atoi( presParam);
906 		p++;
907 	} else
908 		f-> size = 10;
909 
910 	strncpy( f-> name, p, 255);
911 	p = f-> name;
912 	f-> style = 0;
913 	f-> pitch = fpDefault;
914 	for ( i = strlen( p) - 1; i >= 0; i--)  {
915 		if ( p[ i] == '.')  {
916 			if ( stricmp( "Italic",    &p[ i + 1]) == 0) f-> style |= fsItalic;
917 			if ( stricmp( "Bold",      &p[ i + 1]) == 0) f-> style |= fsBold;
918 			if ( stricmp( "Underscore",&p[ i + 1]) == 0) f-> style |= fsUnderlined;
919 			if ( stricmp( "StrikeOut", &p[ i + 1]) == 0) f-> style |= fsStruckOut;
920 			p[ i] = 0;
921 		}
922 	}
923 	f-> undef. width = f-> undef. height = f-> undef. vector = 1;
924 	f-> direction = 0;
925 }
926 
927 PFont
apc_font_default(PFont font)928 apc_font_default( PFont font)
929 {
930 	*font = guts. windowFont;
931 	font-> pitch = fpDefault;
932 	font-> vector = fvDefault;
933 	return font;
934 }
935 
936 int
apc_font_load(Handle self,char * filename)937 apc_font_load( Handle self, char* filename)
938 {
939 	int ret = AddFontResource(( LPCTSTR) filename );
940 	if (ret) hash_store( myfontMan, filename, strlen(filename), (void*)NULL);
941 	return ret;
942 }
943 
944 static Bool recursiveFF         = 0;
945 static Bool recursiveFFEncoding = 0;
946 static Bool recursiveFFPitch    = 0;
947 
948 typedef struct _FEnumStruc
949 {
950 	int           count;
951 	int           passedCount;
952 	int           resValue;
953 	int           heiValue;
954 	int           widValue;
955 	int           fType;
956 	Bool          useWidth;
957 	Bool          wantOutline;
958 	Bool          useVector;
959 	Bool          usePitch;
960 	Bool          forceSize;
961 	Bool          vecId;
962 	Bool          matchILead;
963 	PFont         font;
964 	TEXTMETRICW   tm;
965 	LOGFONTW      lf;
966 	Point         res;
967 	char          name[ LF_FACESIZE];
968 	char          family[ LF_FULLFACESIZE];
969 	Bool          is_utf8_name;
970 	Bool          is_utf8_family;
971 } FEnumStruc, *PFEnumStruc;
972 
973 int CALLBACK
fep(ENUMLOGFONTEXW FAR * e,NEWTEXTMETRICEXW FAR * t,DWORD type,LPARAM _es)974 fep( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICEXW FAR *t, DWORD type, LPARAM _es)
975 {
976 	int ret = 1, copy = 0;
977 	long hei, res;
978 	PFEnumStruc es = (PFEnumStruc) _es;
979 	Font * font = es-> font;
980 
981 	es-> passedCount++;
982 
983 	if ( es-> usePitch)
984 	{
985 		int fpitch = ( t-> ntmTm. tmPitchAndFamily & TMPF_FIXED_PITCH) ? fpVariable : fpFixed;
986 		if ( fpitch != font-> pitch)
987 			return 1; // so this font cannot be selected due pitch pickup failure
988 	}
989 
990 	if ( font-> vector != fvDefault) {
991 		int fvector = (( t-> ntmTm. tmPitchAndFamily & ( TMPF_VECTOR | TMPF_TRUETYPE)) ? fvOutline : fvBitmap);
992 		if ( fvector != font-> vector)
993 			return 1; // so this font cannot be selected due quality pickup failure
994 	}
995 
996 	if ( type & TRUETYPE_FONTTYPE) {
997 		copy = 1;
998 		es-> vecId = 1;
999 		ret = 0; // enough; no further enumeration requred, since Win renders TrueType quite good
1000 					// to not mix these with raster fonts.
1001 		goto EXIT;
1002 	} else if ( !( type & RASTER_FONTTYPE)) {
1003 		copy = 1;
1004 		ret  = 1; // it's vector font; but keep enumeration in case we'll get better match
1005 		es-> vecId = 1;
1006 		goto EXIT;
1007 	}
1008 
1009 	// bitmapped fonts:
1010 	// determining best match for primary measure - size or height
1011 	if ( es-> forceSize) {
1012 		long xs  = ( t-> ntmTm. tmHeight - ( es-> matchILead ? t-> ntmTm. tmInternalLeading : 0))
1013 			* 72.0 / es-> res. y + 0.5;
1014 		hei = ( xs - font-> size) * ( xs - font-> size);
1015 	} else {
1016 		long dv = t-> ntmTm. tmHeight - font-> height - ( es-> matchILead ? 0 : t-> ntmTm. tmInternalLeading);
1017 		hei = dv * dv;
1018 	}
1019 
1020 	// resolution difference
1021 	res = ( t-> ntmTm. tmDigitizedAspectY - es-> res. y) * ( t-> ntmTm. tmDigitizedAspectY - es-> res. y);
1022 
1023 	if ( hei < es-> heiValue) {
1024 		// current height is closer than before...
1025 		es-> heiValue = hei;
1026 		es-> resValue = res;
1027 		if ( es-> useWidth)
1028 			es-> widValue = ( e-> elfLogFont. lfWidth - font-> width) * ( e-> elfLogFont. lfWidth - font-> width);
1029 		copy = 1;
1030 	} else if ( es-> useWidth && ( hei == es-> heiValue)) {
1031 		// height is same close, but width is requested and close that before
1032 		long wid = ( e-> elfLogFont. lfWidth - font-> width) * ( e-> elfLogFont. lfWidth - font-> width);
1033 		if ( wid < es-> widValue) {
1034 			es-> widValue = wid;
1035 			es-> resValue = res;
1036 			copy = 1;
1037 		} else if (( wid == es-> widValue) && ( res < es-> resValue)) {
1038 			// height and width are same close, but resolution is closer
1039 			es-> resValue = res;
1040 			copy = 1;
1041 		}
1042 	} else if (( res < es-> resValue) && ( hei == es-> heiValue)) {
1043 		// height is same close, but resolution is closer
1044 		es-> resValue = res;
1045 		copy = 1;
1046 	}
1047 
1048 EXIT:
1049 
1050 	if ( copy) {
1051 		es-> count++;
1052 		es-> fType = type;
1053 		memcpy( &es-> tm, &t-> ntmTm, sizeof( TEXTMETRICW));
1054 		es->is_utf8_name   = utf8_flag_strncpy( es-> family, e-> elfFullName, LF_FULLFACESIZE);
1055 		memcpy( &es-> lf, &e-> elfLogFont, sizeof( LOGFONT));
1056 		es->is_utf8_family = utf8_flag_strncpy( es-> name, e-> elfLogFont.lfFaceName, LF_FACESIZE);
1057 		wcsncpy( es-> lf.lfFaceName, e-> elfLogFont.lfFaceName, LF_FACESIZE);
1058 	}
1059 
1060 	return ret;
1061 }
1062 
1063 static int
1064 font_font2gp( PFont font, Point res, Bool forceSize, HDC dc);
1065 
1066 static void
font_logfont2textmetric(HDC dc,LOGFONTW * lf,TEXTMETRICW * tm)1067 font_logfont2textmetric( HDC dc, LOGFONTW * lf, TEXTMETRICW * tm)
1068 {
1069 	HFONT hf = SelectObject( dc, CreateFontIndirectW( lf));
1070 	GetTextMetricsW( dc, tm);
1071 	DeleteObject( SelectObject( dc, hf));
1072 }
1073 
1074 int
font_font2gp_internal(PFont font,Point res,Bool forceSize,HDC theDC)1075 font_font2gp_internal( PFont font, Point res, Bool forceSize, HDC theDC)
1076 {
1077 #define out( retVal)  if ( !theDC) dc_free(); return retVal
1078 	FEnumStruc es;
1079 	HDC  dc            = theDC ? theDC : dc_alloc();
1080 	Bool useNameSubplacing = false;
1081 	LOGFONTW elf;
1082 
1083 	if ( !dc) return fvBitmap;
1084 
1085 	memset( &es, 0, sizeof( es));
1086 	es. resValue       = es. heiValue = es. widValue = INT_MAX;
1087 	es. useWidth       = font-> width != 0;
1088 	es. useVector      = font->vector != fvDefault;
1089 	es. wantOutline    = (font-> vector == fvDefault && fabs(font-> direction) > 0.0001) || font->vector == fvOutline;
1090 	es. usePitch       = font-> pitch != fpDefault;
1091 	es. res            = res;
1092 	es. forceSize      = forceSize;
1093 	es. font           = font;
1094 	es. matchILead     = forceSize ? ( font-> size >= 0) : ( font-> height >= 0);
1095 
1096 	useNameSubplacing = es. usePitch || es. useVector;
1097 	if ( font-> height < 0) font-> height *= -1;
1098 	if ( font-> size   < 0) font-> size   *= -1;
1099 
1100 	MultiByteToWideChar(CP_UTF8, 0, font->name, -1, elf.lfFaceName, LF_FACESIZE);
1101 	elf. lfPitchAndFamily = 0;
1102 	elf. lfCharSet = font_encoding2charset( font-> encoding);
1103 	EnumFontFamiliesExW( dc, &elf, (FONTENUMPROCW) fep, ( LPARAM) &es, 0);
1104 
1105 	// check encoding match
1106 	if (( es. passedCount == 0) && ( elf. lfCharSet != DEFAULT_CHARSET) && ( recursiveFFEncoding == 0)) {
1107 		int r;
1108 		font-> name[0] = 0; // any name
1109 		recursiveFFEncoding++;
1110 		r = font_font2gp_internal( font, res, forceSize, dc);
1111 		recursiveFFEncoding--;
1112 		out( r);
1113 	}
1114 
1115 	// checking matched font, if available
1116 	if ( es. count > 0) {
1117 		if ( es. wantOutline) {
1118 			if ( !es. vecId) useNameSubplacing = 1; // try other font if bitmap wouldn't fit
1119 			es. resValue = es. heiValue = INT_MAX;  // cancel bitmap font selection
1120 		}
1121 
1122 		// special synthesized GDI font case
1123 		if (
1124 			es. useWidth && ( es. widValue > 0) &&
1125 			( es. heiValue == 0) &&
1126 			( es. fType & RASTER_FONTTYPE) &&
1127 			( font-> style & fsBold)
1128 		) {
1129 				int r;
1130 				Font xf = *font;
1131 				xf. width--;
1132 				xf. style = 0; // any style could affect tmOverhang
1133 				r = font_font2gp( &xf, res, forceSize, dc);
1134 				if (( r == fvBitmap) && ( xf. width < font-> width)) {
1135 					LOGFONTW lpf;
1136 					TEXTMETRICW tm;
1137 					font_font2logfont( &xf, &lpf);
1138 					lpf. lfWeight = 700;
1139 					font_logfont2textmetric( dc, &lpf, &tm);
1140 					if ( xf. width + tm. tmOverhang == font-> width) {
1141 						font_textmetric2font( &tm, font, true);
1142 						font-> direction = 0;
1143 						font-> size   = xf. size;
1144 						font-> height = xf. height;
1145 						font-> maximalWidth += tm. tmOverhang;
1146 						out( fvBitmap);
1147 					}
1148 				}
1149 			}
1150 
1151 		// have resolution ok? so using raster font mtx
1152 		if (
1153 			( es. heiValue < 2) &&
1154 			( es. fType & RASTER_FONTTYPE) &&
1155 			( !es. useWidth  || (( es. widValue == 0) && ( es. heiValue == 0)))
1156 			)
1157 		{
1158 			font-> height   = es. tm. tmHeight;
1159 			// if synthesized embolding added, we have to reflect that...
1160 			// ( 'cos it increments B-extent of a char cell).
1161 			if ( font-> style & fsBold) {
1162 				LOGFONTW lpf = es. lf;
1163 				TEXTMETRICW tm;
1164 				lpf. lfWeight = 700; // ignore italics, it changes tmOverhang also
1165 				font_logfont2textmetric( dc, &lpf, &tm);
1166 				es. tm. tmMaxCharWidth += tm. tmOverhang;
1167 				es. lf. lfWidth        += tm. tmOverhang;
1168 			}
1169 			font_textmetric2font( &es. tm, font, true);
1170 			font-> direction = 0;
1171 			strncpy( font-> family, es. family, LF_FULLFACESIZE);
1172 			font-> is_utf8.family = es.is_utf8_family;
1173 			font-> size     = ( es. tm. tmHeight - es. tm. tmInternalLeading) * 72.0 / res.y + 0.5;
1174 			font-> width    = es. lf. lfWidth;
1175 			out( fvBitmap);
1176 		}
1177 
1178 		// or vector font - for any purpose?
1179 		// if so, it could guaranteed that font-> height == tmHeight
1180 		if ( es. vecId) {
1181 			LOGFONTW lpf = es. lf;
1182 			TEXTMETRICW tm;
1183 
1184 			// since proportional computation of small items as InternalLeading
1185 			// gives incorrect result, querying the only valid source - GetTextMetrics
1186 			if ( forceSize) {
1187 				lpf. lfHeight = font-> size * res. y / 72.0 + 0.5;
1188 				if ( es. matchILead) lpf. lfHeight *= -1;
1189 			} else
1190 				lpf. lfHeight = es. matchILead ? font-> height : -font-> height;
1191 
1192 			lpf. lfWidth = es. useWidth ? font-> width : 0;
1193 
1194 			font_logfont2textmetric( dc, &lpf, &tm);
1195 			if ( forceSize)
1196 				font-> height = tm. tmHeight;
1197 			else
1198 				font-> size = ( tm. tmHeight - tm. tmInternalLeading) * 72.0 / res. y + 0.5;
1199 
1200 			if ( !es. useWidth)
1201 				font-> width = tm. tmAveCharWidth;
1202 
1203 			font_textmetric2font( &tm, font, true);
1204 			strncpy( font-> family, es. family, LF_FULLFACESIZE);
1205 			font-> is_utf8.family = es.is_utf8_family;
1206 			out( fvOutline);
1207 		}
1208 	}
1209 
1210 	// if strict match not found, use subplacing
1211 	if ( useNameSubplacing && recursiveFFPitch == 0)
1212 	{
1213 		int ret;
1214 		int ogp  = font-> pitch;
1215 
1216 		if ( es. usePitch && es. useVector ) {
1217 			// is this too much? try first without vector
1218 			font-> vector = fvDefault;
1219 			ret = font_font2gp( font, res, forceSize, dc);
1220 			out(ret);
1221 		}
1222 
1223 		// setting some other( maybe other) font name
1224 		if ( es. usePitch) {
1225 			switch ( font->pitch ) {
1226 			case fpFixed:
1227 				strcpy( font-> name, guts. defaultFixedFont);
1228 				break;
1229 			case fpVariable:
1230 				strcpy( font-> name, guts. defaultVariableFont);
1231 				break;
1232 			}
1233 			font-> pitch = fpDefault;
1234 		}
1235 
1236 		if ( es. useVector )
1237 			font-> vector = fvDefault;
1238 
1239 		recursiveFFPitch++;
1240 		ret = font_font2gp( font, res, forceSize, dc);
1241 		// if that alternative match succeeded with name subplaced again, skip
1242 		// that result and use DEFAULT_SYSTEM_FONT match
1243 		if (( ogp == fpFixed) && ( strcmp( font-> name, guts. defaultFixedFont) != 0)) {
1244 			strcpy( font-> name, DEFAULT_SYSTEM_FONT);
1245 			font-> pitch = fpDefault;
1246 			ret = font_font2gp( font, res, forceSize, dc);
1247 		}
1248 		recursiveFFPitch--;
1249 		out( ret);
1250 	}
1251 
1252 	// font not found, so use general representation for height and width
1253 	strcpy( font-> name, guts. defaultSystemFont);
1254 	if ( recursiveFF == 0)
1255 	{
1256 		// trying to catch default font with correct values
1257 		int r;
1258 		recursiveFF++;
1259 		r = font_font2gp( font, res, forceSize, dc);
1260 		recursiveFF--;
1261 		out( r);
1262 	} else {
1263 		int r;
1264 		// if not succeeded, to avoid recursive call use "wild guess".
1265 		// This could be achieved if system does not have "System" font
1266 		*font = guts. windowFont;
1267 		font-> pitch = fpDefault;
1268 		recursiveFF++;
1269 		r = ( recursiveFF < 3) ? font_font2gp( font, res, forceSize, dc) : fvBitmap;
1270 		recursiveFF--;
1271 		out( r);
1272 	}
1273 	return fvBitmap;
1274 #undef out
1275 }
1276 
1277 static int
font_font2gp(PFont font,Point res,Bool forceSize,HDC dc)1278 font_font2gp( PFont font, Point res, Bool forceSize, HDC dc)
1279 {
1280 	Font key;
1281 	Bool addSizeEntry;
1282 	font-> resolution = res. y * 0x10000 + res. x;
1283 	if ( get_font_from_hash( font, forceSize))
1284 		return font->vector;
1285 	memcpy( &key, font, sizeof( Font));
1286 	font_font2gp_internal( font, res, forceSize, dc);
1287 	font-> resolution = res. y * 0x10000 + res. x;
1288 	if ( forceSize) {
1289 		key. height = font-> height;
1290 		addSizeEntry = true;
1291 	} else {
1292 		key. size  = font-> size;
1293 		addSizeEntry = (font->vector > fvBitmap) ? (( key. height == key. width)  || ( key. width == 0)) : true;
1294 	}
1295 	add_font_to_hash( &key, font, addSizeEntry);
1296 	return font->vector;
1297 }
1298 
1299 Bool
apc_font_pick(Handle self,PFont source,PFont dest)1300 apc_font_pick( Handle self, PFont source, PFont dest)
1301 {
1302 	if ( self) objCheck false;
1303 	font_font2gp( dest, apc_gp_get_resolution(self),
1304 		Drawable_font_add( self, source, dest), self ? sys ps : 0);
1305 	return true;
1306 }
1307 
1308 typedef struct {
1309 	List  lst;
1310 	PHash hash;
1311 } Fep2;
1312 
1313 int CALLBACK
fep2(ENUMLOGFONTEXW FAR * e,NEWTEXTMETRICEXW FAR * t,DWORD type,LPARAM _f)1314 fep2( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICEXW FAR *t, DWORD type, LPARAM _f)
1315 {
1316 	PFont fm;
1317 	char name[256];
1318 	Fep2 *f = (Fep2*) _f;
1319 	Bool name_is_utf8;
1320 
1321 	if ( e-> elfLogFont.lfFaceName[0] == '@') return 1; /* skip vertical fonts */
1322 
1323 	name_is_utf8 = utf8_flag_strncpy( name, e-> elfLogFont.lfFaceName, LF_FACESIZE);
1324 
1325 	if ( f-> hash) { /* gross-family enumeration */
1326 		fm = hash_fetch( f-> hash, name, strlen( name));
1327 		if ( fm) {
1328 			char ** enc = (char**) fm-> encoding;
1329 			unsigned char * shift = (unsigned char*)enc + sizeof(char *) - 1;
1330 			if ( *shift + 2 < 256 / sizeof(char*)) {
1331 				*(enc + ++(*shift)) = font_charset2encoding( e-> elfLogFont. lfCharSet);
1332 			}
1333 			return 1;
1334 		}
1335 	}
1336 	fm = ( PFont) malloc( sizeof( Font));
1337 	if ( !fm) return 1;
1338 	memset( fm, 0, sizeof(Font));
1339 	font_textmetric2font(( TEXTMETRICW*) &t-> ntmTm, fm, false);
1340 	if ( f-> hash) { /* multi-encoding format */
1341 		char ** enc = (char**) fm-> encoding;
1342 		unsigned char * shift = (unsigned char*)enc + sizeof(char *) - 1;
1343 		memset( fm-> encoding, 0, 256);
1344 		*(enc + ++(*shift)) = font_charset2encoding( e-> elfLogFont. lfCharSet); /* lfCharSet is A/W-safe */
1345 		hash_store( f-> hash, name, strlen( name), fm);
1346 	}
1347 	fm-> direction = fm-> resolution = 0;
1348 	fm-> is_utf8.name = name_is_utf8;
1349 	strcpy( fm-> name, name);
1350 	fm-> is_utf8.family = utf8_flag_strncpy( fm-> family, e-> elfFullName, LF_FULLFACESIZE);
1351 	list_add( &f-> lst, ( Handle) fm);
1352 	return 1;
1353 }
1354 
1355 PFont
apc_fonts(Handle self,const char * facename,const char * encoding,int * retCount)1356 apc_fonts( Handle self, const char* facename, const char *encoding, int * retCount)
1357 {
1358 	PFont fmtx = NULL;
1359 	int  i;
1360 	HDC  dc;
1361 	Fep2 f;
1362 	Bool hasdc = 0;
1363 	LOGFONTW elf;
1364 	apcErrClear;
1365 
1366 	*retCount = 0;
1367 	if ( self == NULL_HANDLE || self == application) {
1368 		if ( !( dc = dc_alloc())) return NULL;
1369 	}
1370 	else if ( kind_of( self, CPrinter)) {
1371 		if ( !is_opt( optInDraw) && !is_opt( optInDrawInfo)) {
1372 			hasdc = 1;
1373 			CPrinter( self)-> begin_paint_info( self);
1374 		}
1375 		dc = sys ps;
1376 	} else
1377 		return NULL;
1378 
1379 	f. hash = NULL;
1380 	if ( !facename && !encoding)
1381 		if ( !( f. hash = hash_create()))
1382 			return NULL;
1383 	list_create( &f. lst, 256, 256);
1384 	memset( &elf, 0, sizeof( elf));
1385 	MultiByteToWideChar(CP_UTF8, 0, facename ? facename : "", -1, elf.lfFaceName, LF_FACESIZE);
1386 	elf. lfCharSet = font_encoding2charset( encoding);
1387 	EnumFontFamiliesExW( dc, &elf, (FONTENUMPROCW) fep2, ( LPARAM) &f, 0);
1388 	if ( f. hash) {
1389 		hash_destroy( f. hash, false);
1390 		f. hash = NULL;
1391 	}
1392 
1393 	if ( self == NULL_HANDLE || self == application)
1394 		dc_free();
1395 	else if ( hasdc)
1396 		CPrinter( self)-> end_paint_info( self);
1397 
1398 	if ( f. lst. count == 0) goto Nothing;
1399 	fmtx = ( PFont) malloc( f. lst. count * sizeof( Font));
1400 	if ( !fmtx) return NULL;
1401 
1402 	*retCount = f. lst. count;
1403 	for ( i = 0; i < f. lst. count; i++)
1404 		memcpy( &fmtx[ i], ( void *) f. lst. items[ i], sizeof( Font));
1405 	list_delete_all( &f. lst, true);
1406 Nothing:
1407 	list_destroy( &f. lst);
1408 	return fmtx;
1409 }
1410 
1411 
1412 int CALLBACK
fep3(ENUMLOGFONTEXW FAR * e,NEWTEXTMETRICW FAR * t,DWORD type,LPARAM _lst)1413 fep3( ENUMLOGFONTEXW FAR *e, NEWTEXTMETRICW FAR *t, DWORD type, LPARAM _lst)
1414 {
1415 	PHash lst = (PHash) _lst;
1416 	char * str = font_charset2encoding( e-> elfLogFont. lfCharSet);
1417 	hash_store( lst, str, strlen( str), (void*)1);
1418 	return 1;
1419 }
1420 
1421 PHash
apc_font_encodings(Handle self)1422 apc_font_encodings( Handle self )
1423 {
1424 	HDC  dc;
1425 	PHash lst;
1426 	Bool hasdc = 0;
1427 	LOGFONTW elf;
1428 	apcErrClear;
1429 
1430 	if ( self == NULL_HANDLE || self == application) {
1431 		if ( !( dc = dc_alloc())) return NULL;
1432 	}
1433 	else if ( kind_of( self, CPrinter)) {
1434 		if ( !is_opt( optInDraw) && !is_opt( optInDrawInfo)) {
1435 			hasdc = 1;
1436 			CPrinter( self)-> begin_paint_info( self);
1437 		}
1438 		dc = sys ps;
1439 	} else
1440 		return NULL;
1441 
1442 	lst = hash_create();
1443 	memset( &elf, 0, sizeof( elf));
1444 	elf. lfCharSet = DEFAULT_CHARSET;
1445 	EnumFontFamiliesExW( dc, &elf, (FONTENUMPROCW) fep3, ( LPARAM) lst, 0);
1446 
1447 	if ( self == NULL_HANDLE || self == application)
1448 		dc_free();
1449 	else if ( hasdc)
1450 		CPrinter( self)-> end_paint_info( self);
1451 
1452 	return lst;
1453 }
1454 
1455 
1456 // Font end
1457 // Colors section
1458 
1459 
1460 #define stdDisabled  COLOR_GRAYTEXT        ,  COLOR_BTNFACE
1461 #define stdHilite    COLOR_HIGHLIGHTTEXT   ,  COLOR_HIGHLIGHT
1462 #define std3d        COLOR_BTNHIGHLIGHT    ,  COLOR_BTNSHADOW
1463 
1464 static Handle buttonScheme[] = {
1465 	COLOR_BTNTEXT,   COLOR_BTNFACE,
1466 	COLOR_BTNTEXT,   COLOR_BTNFACE,
1467 	COLOR_GRAYTEXT,  COLOR_BTNFACE,
1468 	std3d
1469 };
1470 static Handle sliderScheme[] = {
1471 	COLOR_WINDOWTEXT,       COLOR_SCROLLBAR,
1472 	COLOR_WINDOWTEXT,       COLOR_SCROLLBAR,
1473 	stdDisabled,
1474 	std3d
1475 };
1476 
1477 static Handle dialogScheme[] = {
1478 	COLOR_WINDOWTEXT, COLOR_BTNFACE,
1479 	COLOR_CAPTIONTEXT, COLOR_ACTIVECAPTION,
1480 	COLOR_INACTIVECAPTIONTEXT, COLOR_INACTIVECAPTION,
1481 	std3d
1482 };
1483 static Handle staticScheme[] = {
1484 	COLOR_WINDOWTEXT, COLOR_BTNFACE,
1485 	COLOR_WINDOWTEXT, COLOR_BTNFACE,
1486 	stdDisabled,
1487 	std3d
1488 };
1489 static Handle editScheme[] = {
1490 	COLOR_WINDOWTEXT, COLOR_WINDOW,
1491 	stdHilite,
1492 	stdDisabled,
1493 	std3d
1494 };
1495 static Handle menuScheme[] = {
1496 	COLOR_MENUTEXT, COLOR_MENU,
1497 	stdHilite,
1498 	stdDisabled,
1499 	std3d
1500 };
1501 
1502 static Handle scrollScheme[] = {
1503 	COLOR_WINDOWTEXT,    COLOR_BTNFACE,
1504 	stdHilite,
1505 	stdDisabled,
1506 	std3d
1507 };
1508 
1509 static Handle windowScheme[] = {
1510 	COLOR_WINDOWTEXT,  COLOR_BTNFACE,
1511 	COLOR_CAPTIONTEXT, COLOR_ACTIVECAPTION,
1512 	COLOR_INACTIVECAPTIONTEXT, COLOR_INACTIVECAPTION,
1513 	std3d
1514 };
1515 static Handle customScheme[] = {
1516 	COLOR_WINDOWTEXT, COLOR_BTNFACE,
1517 	stdHilite,
1518 	stdDisabled,
1519 	std3d
1520 };
1521 
1522 static Handle ctx_wc2SCHEME[] =
1523 {
1524 	wcButton    , ( Handle) &buttonScheme,
1525 	wcCheckBox  , ( Handle) &buttonScheme,
1526 	wcRadio     , ( Handle) &buttonScheme,
1527 	wcDialog    , ( Handle) &dialogScheme,
1528 	wcSlider    , ( Handle) &sliderScheme,
1529 	wcLabel     , ( Handle) &staticScheme,
1530 	wcInputLine , ( Handle) &editScheme,
1531 	wcEdit      , ( Handle) &editScheme,
1532 	wcListBox   , ( Handle) &editScheme,
1533 	wcCombo     , ( Handle) &editScheme,
1534 	wcMenu      , ( Handle) &menuScheme,
1535 	wcPopup     , ( Handle) &menuScheme,
1536 	wcScrollBar , ( Handle) &scrollScheme,
1537 	wcWindow    , ( Handle) &windowScheme,
1538 	wcWidget    , ( Handle) &customScheme,
1539 	endCtx
1540 };
1541 
1542 
1543 long
remap_color(long clr,Bool toSystem)1544 remap_color( long clr, Bool toSystem)
1545 {
1546 	if ( toSystem && ( clr & clSysFlag)) {
1547 		long c = clr;
1548 		Handle * scheme = ( Handle *) ctx_remap_def( clr & wcMask, ctx_wc2SCHEME, true, ( Handle) &customScheme);
1549 		if (( clr = ( clr & ~wcMask)) > clMaxSysColor) clr = clMaxSysColor;
1550 		if ( clr == clSet || clr == clInvalid) return 0xFFFFFF;
1551 		if ( clr == clClear) return 0;
1552 		c = GetSysColor( scheme[( clr & clSysMask) - 1]);
1553 		return c;
1554 	} else {
1555 		PRGBColor cp = ( PRGBColor) &clr;
1556 		unsigned char sw = cp-> r;
1557 		cp-> r = cp-> b;
1558 		cp-> b = sw;
1559 		return clr;
1560 	}
1561 }
1562 
1563 Color
apc_lookup_color(const char * colorName)1564 apc_lookup_color( const char * colorName)
1565 {
1566 	char buf[ 256];
1567 	char *b;
1568 	int len;
1569 
1570 #define xcmp( name, stlen, retval)  if (( len == stlen) && ( strcmp( name, buf) == 0)) return retval
1571 
1572 	strncpy( buf, colorName, 255);
1573 	len = strlen( buf);
1574 	for ( b = buf; *b; b++) *b = tolower(*b);
1575 
1576 	switch( buf[0]) {
1577 	case 'a':
1578 		xcmp( "aqua", 4, 0x00FFFF);
1579 		xcmp( "azure", 5, ARGB(240,255,255));
1580 		break;
1581 	case 'b':
1582 		xcmp( "black", 5, 0x000000);
1583 		xcmp( "blanchedalmond", 14, ARGB( 255,235,205));
1584 		xcmp( "blue", 4, 0x000080);
1585 		xcmp( "brown", 5, 0x808000);
1586 		xcmp( "beige", 5, ARGB(245,245,220));
1587 		break;
1588 	case 'c':
1589 		xcmp( "cyan", 4, 0x008080);
1590 		xcmp( "chocolate", 9, ARGB(210,105,30));
1591 		break;
1592 	case 'd':
1593 		xcmp( "darkgray", 8, 0x404040);
1594 		break;
1595 	case 'e':
1596 		break;
1597 	case 'f':
1598 		xcmp( "fuchsia", 7, 0xFF00FF);
1599 		break;
1600 	case 'g':
1601 		xcmp( "green", 5, 0x008000);
1602 		xcmp( "gray", 4, 0x808080);
1603 		xcmp( "gray80", 6, ARGB(204,204,204));
1604 		xcmp( "gold", 4, ARGB(255,215,0));
1605 		break;
1606 	case 'h':
1607 		xcmp( "hotpink", 7, ARGB(255,105,180));
1608 		break;
1609 	case 'i':
1610 		xcmp( "ivory", 5, ARGB(255,255,240));
1611 		break;
1612 	case 'j':
1613 		break;
1614 	case 'k':
1615 		xcmp( "khaki", 5, ARGB(240,230,140));
1616 		break;
1617 	case 'l':
1618 		xcmp( "lime", 4, 0x00FF00);
1619 		xcmp( "lightgray", 9, 0xC0C0C0);
1620 		xcmp( "lightblue", 9, 0x0000FF);
1621 		xcmp( "lightgreen", 10, 0x00FF00);
1622 		xcmp( "lightcyan", 9, 0x00FFFF);
1623 		xcmp( "lightmagenta", 12, 0xFF00FF);
1624 		xcmp( "lightred", 8, 0xFF0000);
1625 		xcmp( "lemon", 5, ARGB(255,250,205));
1626 		break;
1627 	case 'm':
1628 		xcmp( "maroon", 6, 0x800000);
1629 		xcmp( "magenta", 7, 0x800080);
1630 		break;
1631 	case 'n':
1632 		xcmp( "navy", 4, 0x000080);
1633 		break;
1634 	case 'o':
1635 		xcmp( "olive", 5, 0x808000);
1636 		xcmp( "orange", 6, ARGB(255,165,0));
1637 		break;
1638 	case 'p':
1639 		xcmp( "purple", 6, 0x800080);
1640 		xcmp( "peach", 5, ARGB(255,218,185));
1641 		xcmp( "peru", 4, ARGB(205,133,63));
1642 		xcmp( "pink", 4, ARGB(255,192,203));
1643 		xcmp( "plum", 4, ARGB(221,160,221));
1644 		break;
1645 	case 'q':
1646 		break;
1647 	case 'r':
1648 		xcmp( "red", 3, 0x800000);
1649 		xcmp( "royalblue", 9, ARGB(65,105,225));
1650 		break;
1651 	case 's':
1652 		xcmp( "silver", 6, 0xC0C0C0);
1653 		xcmp( "sienna", 6, ARGB(160,82,45));
1654 		break;
1655 	case 't':
1656 		xcmp( "teal", 4, 0x008080);
1657 		xcmp( "turquoise", 9, ARGB(64,224,208));
1658 		xcmp( "tan", 3, ARGB(210,180,140));
1659 		xcmp( "tomato", 6, ARGB(255,99,71));
1660 		break;
1661 	case 'u':
1662 		break;
1663 	case 'w':
1664 		xcmp( "white", 5, 0xFFFFFF);
1665 		xcmp( "wheat", 5, ARGB(245,222,179));
1666 		break;
1667 	case 'v':
1668 		xcmp( "violet", 6, ARGB(238,130,238));
1669 		break;
1670 	case 'x':
1671 		break;
1672 	case 'y':
1673 		xcmp( "yellow", 6, 0xFFFF00);
1674 		break;
1675 	case 'z':
1676 		break;
1677 	}
1678 
1679 #undef xcmp
1680 
1681 	return clInvalid;
1682 }
1683 
1684 // Colors end
1685 // Miscellaneous
1686 
1687 static HDC cachedScreenDC = NULL;
1688 static int cachedScreenRC = 0;
1689 static HDC cachedCompatDC = NULL;
1690 static int cachedCompatRC = 0;
1691 
1692 
dc_alloc()1693 HDC dc_alloc()
1694 {
1695 	if ( cachedScreenRC++ == 0) {
1696 		if ( !( cachedScreenDC = GetDC( 0)))
1697 			apiErr;
1698 	}
1699 	return cachedScreenDC;
1700 }
1701 
dc_free()1702 void dc_free()
1703 {
1704 	if ( --cachedScreenRC <= 0)
1705 		ReleaseDC( 0, cachedScreenDC);
1706 	if ( cachedScreenRC < 0)
1707 		cachedScreenRC = 0;
1708 }
1709 
dc_compat_alloc(HDC compatDC)1710 HDC dc_compat_alloc( HDC compatDC)
1711 {
1712 	if ( cachedCompatRC++ == 0) {
1713 		if ( !( cachedCompatDC = CreateCompatibleDC( compatDC)))
1714 			apiErr;
1715 	}
1716 	return cachedCompatDC;
1717 }
1718 
dc_compat_free()1719 void dc_compat_free()
1720 {
1721 	if ( --cachedCompatRC <= 0)
1722 		DeleteDC( cachedCompatDC);
1723 	if ( cachedCompatRC < 0)
1724 		cachedCompatRC = 0;
1725 }
1726 
1727 void
hwnd_enter_paint(Handle self)1728 hwnd_enter_paint( Handle self)
1729 {
1730 	Point res;
1731 	GetObject( sys stockPen   = GetCurrentObject( sys ps, OBJ_PEN),
1732 		sizeof( LOGPEN), &sys stylus. pen);
1733 	GetObject( sys stockBrush = GetCurrentObject( sys ps, OBJ_BRUSH),
1734 		sizeof( LOGBRUSH), &sys stylus. brush);
1735 	sys stockFont      = GetCurrentObject( sys ps, OBJ_FONT);
1736 	if ( !sys stockPalette)
1737 		sys stockPalette = GetCurrentObject( sys ps, OBJ_PAL);
1738 	font_free( sys fontResource, false);
1739 	sys stylusResource = NULL;
1740 	sys stylusGPResource = NULL;
1741 	sys fontResource   = NULL;
1742 	sys stylusFlags    = 0;
1743 	sys stylus. extPen. actual = false;
1744 	apt_set( aptDCChangeLock);
1745 	sys bpp = GetDeviceCaps( sys ps, BITSPIXEL);
1746 	if ( is_apt( aptWinPS) && self != application) {
1747 		apc_gp_set_color( self, sys viewColors[ ciFore]);
1748 		apc_gp_set_back_color( self, sys viewColors[ ciBack]);
1749 	} else {
1750 		apc_gp_set_color( self, remap_color(sys lbs[0],false));
1751 		apc_gp_set_back_color( self, remap_color(sys lbs[1],false));
1752 	}
1753 
1754 	if ( sys psd == NULL) sys psd = ( PPaintSaveData) malloc( sizeof( PaintSaveData));
1755 	if ( sys psd == NULL) return;
1756 
1757 	apc_gp_set_alpha( self, sys alpha);
1758 	apc_gp_set_antialias( self, is_apt( aptGDIPlus));
1759 	apc_gp_set_text_opaque( self, is_apt( aptTextOpaque));
1760 	apc_gp_set_text_out_baseline( self, is_apt( aptTextOutBaseline));
1761 	apc_gp_set_fill_mode( self, sys fillMode);
1762 	apc_gp_set_fill_pattern_offset( self, sys fillPatternOffset);
1763 	apc_gp_set_line_width( self, sys lineWidth);
1764 	apc_gp_set_line_end( self, sys lineEnd);
1765 	apc_gp_set_line_join( self, sys lineJoin);
1766 	apc_gp_set_line_pattern( self,
1767 		( Byte*)(( sys linePatternLen > sizeof(sys linePattern)) ? sys linePattern : ( Byte*)&sys linePattern),
1768 		sys linePatternLen);
1769 	apc_gp_set_miter_limit( self, sys miterLimit);
1770 	apc_gp_set_rop( self, sys rop);
1771 	apc_gp_set_rop2( self, sys rop2);
1772 	apc_gp_set_transform( self, sys transform. x, sys transform. y);
1773 	apc_gp_set_fill_pattern( self, sys fillPattern2);
1774 	sys psd-> alpha          = sys alpha;
1775 	sys psd-> antialias      = is_apt( aptGDIPlus);
1776 	sys psd-> font           = var font;
1777 	sys psd-> fillMode       = sys fillMode;
1778 	sys psd-> fillPatternOffset = sys fillPatternOffset;
1779 	sys psd-> lineWidth      = sys lineWidth;
1780 	sys psd-> lineEnd        = sys lineEnd;
1781 	sys psd-> lineJoin       = sys lineJoin;
1782 	sys psd-> linePattern    = sys linePattern;
1783 	sys psd-> linePatternLen = sys linePatternLen;
1784 	sys psd-> rop            = sys rop;
1785 	sys psd-> rop2           = sys rop2;
1786 	sys psd-> transform      = sys transform;
1787 	sys psd-> textOpaque     = is_apt( aptTextOpaque);
1788 	sys psd-> textOutB       = is_apt( aptTextOutBaseline);
1789 	sys psd-> antialias      = is_apt( aptGDIPlus);
1790 
1791 	apt_clear( aptDCChangeLock);
1792 	stylus_change( self);
1793 	apc_gp_set_font( self, &var font);
1794 	res = apc_gp_get_resolution(self);
1795 	var font. resolution = res. y * 0x10000 + res. x;
1796 	SetStretchBltMode( sys ps, COLORONCOLOR);
1797 }
1798 
1799 void
hwnd_leave_paint(Handle self)1800 hwnd_leave_paint( Handle self)
1801 {
1802 	if ( sys graphics) {
1803 		GdipDeleteGraphics(sys graphics);
1804 		sys graphics = NULL;
1805 	}
1806 	SelectObject( sys ps,  sys stockPen);
1807 	SelectObject( sys ps,  sys stockBrush);
1808 	SelectObject( sys ps,  sys stockFont);
1809 	SelectPalette( sys ps, sys stockPalette, 0);
1810 	sys stockPen = NULL;
1811 	sys stockBrush = NULL;
1812 	sys stockFont = NULL;
1813 	sys stockPalette = NULL;
1814 	stylus_free( sys stylusResource, false);
1815 	if ( sys opaquePen ) {
1816 		DeleteObject( sys opaquePen );
1817 		sys opaquePen = NULL;
1818 	}
1819 	if ( sys psd != NULL) {
1820 		var font           = sys psd-> font;
1821 		sys alpha          = sys psd-> alpha;
1822 		sys fillMode       = sys psd-> fillMode;
1823 		sys fillPatternOffset  = sys psd-> fillPatternOffset;
1824 		sys lineWidth      = sys psd-> lineWidth;
1825 		sys lineEnd        = sys psd-> lineEnd;
1826 		sys lineJoin       = sys psd-> lineJoin;
1827 		sys linePattern    = sys psd-> linePattern;
1828 		sys linePatternLen = sys psd-> linePatternLen;
1829 		sys rop            = sys psd-> rop;
1830 		sys rop2           = sys psd-> rop2;
1831 		sys transform      = sys psd-> transform;
1832 		apt_assign( aptTextOpaque,      sys psd-> textOpaque);
1833 		apt_assign( aptTextOutBaseline, sys psd-> textOutB);
1834 		apt_assign( aptGDIPlus,         sys psd-> antialias);
1835 		free( sys psd);
1836 		sys psd = NULL;
1837 	}
1838 	sys bpp = 0;
1839 }
1840 
1841 Bool
hwnd_repaint_layered(Handle self,Bool now)1842 hwnd_repaint_layered( Handle self, Bool now )
1843 {
1844 	Event ev;
1845 	Handle top;
1846 
1847 	top = hwnd_layered_top_level( self );
1848 	if ( top && top != self && dsys(top) options. aptLayered )
1849 		return hwnd_repaint_layered(top, now);
1850 
1851 	if ( !is_apt( aptLayered)) return false;
1852 
1853 	if ( !now && !is_apt( aptSyncPaint) ) {
1854 		if ( !is_apt( aptRepaintPending )) {
1855 			apt_set( aptRepaintPending );
1856 			PostMessage(( HWND) var handle, WM_REPAINT_LAYERED, 0, 0);
1857 		}
1858 		return false;
1859 	}
1860 
1861 	apt_clear( aptRepaintPending );
1862 	ev. cmd = cmPaint;
1863 	CWidget(self)-> message( self, &ev);
1864 
1865 	return true;
1866 }
1867 
1868 Handle
hwnd_top_level(Handle self)1869 hwnd_top_level( Handle self)
1870 {
1871 	while ( self) {
1872 		if ( sys className == WC_FRAME) return self;
1873 		self = var owner;
1874 	}
1875 	return NULL_HANDLE;
1876 }
1877 
1878 Handle
hwnd_frame_top_level(Handle self)1879 hwnd_frame_top_level( Handle self)
1880 {
1881 	while ( self && ( self != application)) {
1882 		if (( sys className == WC_FRAME) ||
1883 			( !is_apt( aptClipOwner) && ( var owner != application))) return self;
1884 		self = var owner;
1885 	}
1886 	return NULL_HANDLE;
1887 }
1888 
1889 Handle
hwnd_layered_top_level(Handle self)1890 hwnd_layered_top_level( Handle self)
1891 {
1892 	while ( self && ( self != application)) {
1893 		if (( sys className == WC_FRAME) ||
1894 			(!is_apt( aptClipOwner) || (var owner == application))) return self;
1895 		self = var owner;
1896 	}
1897 	return NULL_HANDLE;
1898 }
1899 
1900 typedef struct _ModData
1901 {
1902 	BYTE  ks  [ 256];
1903 	BYTE  kss [ 3];
1904 	BYTE *gks;
1905 } ModData;
1906 
1907 
1908 BYTE *
mod_select(int mod)1909 mod_select( int mod)
1910 {
1911 	ModData * ks;
1912 
1913 	ks = ( ModData*) malloc( sizeof( ModData));
1914 	if ( !ks) return NULL;
1915 
1916 	GetKeyboardState( ks-> ks);
1917 	ks-> kss[ 0]   = ks-> ks[ VK_MENU];
1918 	ks-> kss[ 1]   = ks-> ks[ VK_CONTROL];
1919 	ks-> kss[ 2]   = ks-> ks[ VK_SHIFT];
1920 	ks-> ks[ VK_MENU   ] = ( mod & kmAlt  ) ? 0x80 : 0;
1921 	ks-> ks[ VK_CONTROL] = ( mod & kmCtrl ) ? 0x80 : 0;
1922 	ks-> ks[ VK_SHIFT  ] = ( mod & kmShift) ? 0x80 : 0;
1923 	SetKeyboardState( ks-> ks);
1924 	ks-> gks = guts. currentKeyState;
1925 	guts. currentKeyState = ks-> ks;
1926 	return ( BYTE*) ks;
1927 }
1928 
1929 void
mod_free(BYTE * modState)1930 mod_free( BYTE * modState)
1931 {
1932 	ModData * ks = ( ModData*) modState;
1933 	if ( !ks) return;
1934 
1935 	ks-> ks[ VK_MENU   ] = ks-> kss[ 0];
1936 	ks-> ks[ VK_CONTROL] = ks-> kss[ 1];
1937 	ks-> ks[ VK_SHIFT  ] = ks-> kss[ 2];
1938 	SetKeyboardState( ks-> ks);
1939 	guts. currentKeyState = ks-> gks;
1940 	free( ks);
1941 }
1942 
1943 typedef struct _SzList
1944 {
1945 	List l;
1946 	int  sz;
1947 	PRGBColor p;
1948 } SzList, *PSzList;
1949 
1950 static Bool
pal_count(Handle window,Handle self,PSzList l)1951 pal_count( Handle window, Handle self, PSzList l)
1952 {
1953 	if ( !is_apt( aptClipOwner) && ( window != application))
1954 		return false;
1955 	if ( var palSize > 0) {
1956 		list_add( &l->l, self);
1957 		l->sz += var palSize;
1958 	}
1959 	if ( var widgets. count > 0)
1960 		CWidget( self)-> first_that( self, pal_count, l);
1961 	return false;
1962 }
1963 
1964 static Bool
pal_collect(Handle self,PSzList l)1965 pal_collect( Handle self, PSzList l)
1966 {
1967 	memcpy( l-> p, var palette, var palSize * sizeof( RGBColor));
1968 	l-> p  += var palSize;
1969 	return false;
1970 }
1971 
1972 static Bool
repaint_all(Handle owner,Handle self,void * dummy)1973 repaint_all( Handle owner, Handle self, void * dummy)
1974 {
1975 	objCheck false;
1976 	if ( !is_apt( aptClipOwner))
1977 		return false;
1978 	if ( !is_apt( aptTransparent)) {
1979 		if ( !InvalidateRect(( HWND) var handle, NULL, false)) apiErr;
1980 		if ( is_apt( aptSyncPaint) && !apcUpdateWindow(( HWND) var handle)) apiErr;
1981 		objCheck false;
1982 		var self-> first_that( self, repaint_all, NULL);
1983 	}
1984 	process_transparents( self);
1985 	return false;
1986 }
1987 
1988 void
hwnd_repaint(Handle self)1989 hwnd_repaint( Handle self)
1990 {
1991 	objCheck;
1992 	if ( !InvalidateRect (( HWND) var handle, NULL, false)) apiErr;
1993 	if ( is_apt( aptSyncPaint) && !apcUpdateWindow(( HWND) var handle)) apiErr;
1994 	objCheck;
1995 	var self-> first_that( self, repaint_all, NULL);
1996 	process_transparents( self);
1997 }
1998 
1999 Bool
palette_change(Handle self)2000 palette_change( Handle self)
2001 {
2002 	SzList l;
2003 	PRGBColor p;
2004 	PRGBColor d;
2005 	int nColors = ( 1 << (
2006 		guts. displayBMInfo. bmiHeader. biBitCount *
2007 		guts. displayBMInfo. bmiHeader. biPlanes
2008 	)) & 0x1FF;
2009 	int i;
2010 	HPALETTE pal;
2011 	XLOGPALETTE xlp = {0x300};
2012 	HDC dc;
2013 
2014 	if ( nColors == 0)
2015 		return false;
2016 
2017 	self = hwnd_frame_top_level( self);
2018 	if ( self == NULL_HANDLE) return false;
2019 
2020 	list_create( &l.l, 32, 32);
2021 	l. sz = 0;
2022 	if ( var palSize > 0) {
2023 		list_add( &l.l, self);
2024 		l.sz += var palSize;
2025 	}
2026 	if ( var widgets. count > 0)
2027 		CWidget( self)-> first_that( self, pal_count, &l);
2028 
2029 	if ( l. l. count == 0) {
2030 		list_destroy( &l.l);
2031 		hwnd_repaint( self);
2032 		return false;
2033 	}
2034 
2035 
2036 	xlp. palNumEntries = l. sz;
2037 	p = ( PRGBColor) malloc( sizeof( RGBColor) * l. sz);
2038 	if ( !p) {
2039 		list_destroy( &l.l);
2040 		hwnd_repaint( self);
2041 		return false;
2042 	}
2043 
2044 	d = ( PRGBColor) malloc( sizeof( RGBColor) * nColors);
2045 	if ( !d) {
2046 		free( p);
2047 		list_destroy( &l.l);
2048 		hwnd_repaint( self);
2049 		return false;
2050 	}
2051 
2052 	l. p = p;
2053 	list_first_that( &l.l, pal_collect, &l);
2054 	cm_squeeze_palette( p, xlp. palNumEntries, d, nColors);
2055 	xlp. palNumEntries = nColors;
2056 
2057 	for ( i = 0; i < nColors; i++) {
2058 		xlp. palPalEntry[ i]. peRed    = d[ i]. r;
2059 		xlp. palPalEntry[ i]. peGreen  = d[ i]. g;
2060 		xlp. palPalEntry[ i]. peBlue   = d[ i]. b;
2061 		xlp. palPalEntry[ i]. peFlags  = 0;
2062 	}
2063 
2064 	free( d);
2065 	free( p);
2066 
2067 	pal = CreatePalette(( LOGPALETTE *) &xlp);
2068 
2069 	dc  = GetDC( HANDLE);
2070 	pal  = SelectPalette( dc, pal, 0);
2071 	RealizePalette( dc);
2072 	DeleteObject( SelectPalette( dc, pal, 0));
2073 	ReleaseDC( HANDLE, dc);
2074 
2075 	hwnd_repaint( self);
2076 
2077 	list_destroy( &l.l);
2078 	return true;
2079 }
2080 
2081 int
palette_match_color(XLOGPALETTE * lp,long clr,int * diffFactor)2082 palette_match_color( XLOGPALETTE * lp, long clr, int * diffFactor)
2083 {
2084 	int diff = 0x10000, cdiff = 0, ret = 0, nCol = lp-> palNumEntries;
2085 	RGBColor color;
2086 
2087 	if ( nCol == 0) {
2088 		if ( diffFactor) *diffFactor = 0;
2089 		return clr;
2090 	}
2091 
2092 	color. r = clr & 0xFF;
2093 	color. g = ( clr >> 8)  & 0xFF;
2094 	color. b = ( clr >> 16) & 0xFF;
2095 
2096 	while( nCol--)
2097 	{
2098 		int dr=abs((int)color. r - (int)lp-> palPalEntry[ nCol]. peRed),
2099 			dg=abs((int)color. g - (int)lp-> palPalEntry[ nCol]. peGreen),
2100 			db=abs((int)color. b - (int)lp-> palPalEntry[ nCol]. peBlue);
2101 		cdiff=dr*dr+dg*dg+db*db;
2102 		if ( cdiff < diff) {
2103 			ret  = nCol;
2104 			diff = cdiff;
2105 			if ( cdiff == 0) break;
2106 		}
2107 	}
2108 
2109 	if ( diffFactor) *diffFactor = cdiff;
2110 	return ret;
2111 }
2112 
2113 
2114 long
palette_match(Handle self,long clr)2115 palette_match( Handle self, long clr)
2116 {
2117 	XLOGPALETTE lp;
2118 	int cdiff;
2119 	RGBColor color;
2120 
2121 	lp. palNumEntries = GetPaletteEntries( sys pal, 0, 256, lp. palPalEntry);
2122 
2123 	if ( lp. palNumEntries == 0) {
2124 		apiErr;
2125 		return clr;
2126 	}
2127 
2128 	color. r = clr & 0xFF;
2129 	color. g = ( clr >> 8)  & 0xFF;
2130 	color. b = ( clr >> 16) & 0xFF;
2131 
2132 	palette_match_color( &lp, clr, &cdiff);
2133 
2134 	if ( cdiff >= COLOR_TOLERANCE)
2135 		return clr;
2136 
2137 	lp. palNumEntries = GetSystemPaletteEntries( sys ps, 0, 256, lp. palPalEntry);
2138 
2139 	palette_match_color( &lp, clr, &cdiff);
2140 
2141 	if ( cdiff >= COLOR_TOLERANCE)
2142 		return clr;
2143 
2144 	return PALETTERGB( color.r, color.g, color.b);
2145 }
2146 
2147 int
arc_completion(double * angleStart,double * angleEnd,int * needFigure)2148 arc_completion( double * angleStart, double * angleEnd, int * needFigure)
2149 {
2150 	int max;
2151 	long diff = ((long)( fabs( *angleEnd - *angleStart) * 1000 + 0.5));
2152 
2153 	if ( diff == 0) {
2154 		*needFigure = false;
2155 		return 0;
2156 	}
2157 	diff /= 1000;
2158 
2159 	while ( *angleStart > *angleEnd)
2160 		*angleEnd += 360;
2161 
2162 	while ( *angleStart < 0) {
2163 		*angleStart += 360;
2164 		*angleEnd   += 360;
2165 	}
2166 
2167 	while ( *angleStart >= 360) {
2168 		*angleStart -= 360;
2169 		*angleEnd   -= 360;
2170 	}
2171 
2172 	while ( *angleEnd >= *angleStart + 360)
2173 		*angleEnd -= 360;
2174 
2175 	if ( diff < 360) {
2176 		*needFigure = true;
2177 		return 0;
2178 	}
2179 
2180 	max = (int)(diff / 360);
2181 	*needFigure = ( max * 360) != diff;
2182 	return ( max % 2) ? 1 : 2;
2183 }
2184 
2185 
2186 #ifdef __cplusplus
2187 }
2188 #endif
2189