1 /***********************************************************/
2 /*                                                         */
3 /*  System dependent graphics (unix, x11)                  */
4 /*                                                         */
5 /***********************************************************/
6 
7 #include "unix/guts.h"
8 #include "Image.h"
9 
10 #define SORT(a,b)	{ int swp; if ((a) > (b)) { swp=(a); (a)=(b); (b)=swp; }}
11 #define REVERT(a)	(XX-> size. y - (a) - 1)
12 #define SHIFT(a,b)	{ (a) += XX-> gtransform. x + XX-> btransform. x; \
13 			(b) += XX-> gtransform. y + XX-> btransform. y; }
14 #define RANGE(a)        { if ((a) < -16383) (a) = -16383; else if ((a) > 16383) a = 16383; }
15 #define RANGE2(a,b)     RANGE(a) RANGE(b)
16 
17 typedef struct {
18 	int default_char1;
19 	int default_char2;
20 	int offset;
21 	XFontStruct *fs;
22 } CharStructABC;
23 
24 static void
init_xchar_abc(XFontStruct * fs,CharStructABC * s)25 init_xchar_abc( XFontStruct * fs, CharStructABC * s)
26 {
27 	s-> fs = fs;
28 	s-> default_char1 = fs-> default_char >> 8;
29 	s-> default_char2 = fs-> default_char & 0xff;
30 	s-> offset        = fs-> max_char_or_byte2 - fs-> min_char_or_byte2 + 1;
31 
32 	if (
33 		s-> default_char2 < fs-> min_char_or_byte2 ||
34 		s-> default_char2 > fs-> max_char_or_byte2 ||
35 		s-> default_char1 < fs-> min_byte1 ||
36 		s-> default_char1 > fs-> max_byte1
37 	) {
38 		s-> default_char1 = fs-> min_byte1;
39 		s-> default_char2 = fs-> min_char_or_byte2;
40 	}
41 }
42 
43 static XCharStruct *
xchar_struct(CharStructABC * s,unsigned int codepoint)44 xchar_struct( CharStructABC * s, unsigned int codepoint)
45 {
46 	XCharStruct * cs;
47 	int i1 = codepoint >> 8;
48 	int i2 = codepoint & 0xff;
49 	XFontStruct * fs = s-> fs;
50 
51 	if ( !fs-> per_char)
52 		cs = &fs-> min_bounds;
53 	else if (
54 		i2 < fs-> min_char_or_byte2 ||
55 		i2 > fs-> max_char_or_byte2 ||
56 		i1 < fs-> min_byte1 ||
57 		i1 > fs-> max_byte1
58 	)
59 		cs = fs-> per_char +
60 			(s->default_char1 - fs-> min_byte1) * s->offset +
61 			s->default_char2 - fs-> min_char_or_byte2;
62 	else
63 		cs = fs-> per_char +
64 			(i1 - fs-> min_byte1) * s->offset +
65 			i2 - fs-> min_char_or_byte2;
66 
67 	return cs;
68 }
69 
70 static int need_swap_bytes = -1;
71 static void
swap_bytes(register uint16_t * area,int len)72 swap_bytes( register uint16_t * area, int len )
73 {
74 	if ( need_swap_bytes < 0 ) {
75 		XChar2b  b = { 0x1, 0x23 };
76 		uint16_t a = 0x123, *pb = (uint16_t*) &b;
77 		need_swap_bytes = a != *pb;
78 	}
79 	if ( need_swap_bytes ) while (len-- > 0) {
80 		register uint16_t x = *area;
81 		*(area++) = (( x & 0xff ) << 8) | (x >> 8);
82 	}
83 }
84 #define SWAP_BYTES(area,len) if (need_swap_bytes) swap_bytes(area,len)
85 
86 
87 static Point
gp_get_text_overhangs(Handle self,const char * text,int len,int flags)88 gp_get_text_overhangs( Handle self, const char *text, int len, int flags)
89 {
90 	DEFXX;
91 	Point ret;
92 	if ( len > 0) {
93 		XCharStruct * cs;
94 		cs = prima_char_struct( XX-> font-> fs, (void*) text, flags & (toUTF8 | toGlyphs));
95 		ret. x = ( cs-> lbearing < 0) ? - cs-> lbearing : 0;
96 		text += (len - 1) * ((flags & (toUTF8 | toGlyphs)) ? 2 : 1);
97 		cs = prima_char_struct( XX-> font-> fs, (void*) text, flags & (toUTF8 | toGlyphs));
98 		ret. y = (( cs-> width - cs-> rbearing) < 0) ? cs-> rbearing - cs-> width : 0;
99 	} else
100 		ret. x = ret. y = 0;
101 	return ret;
102 }
103 
104 static int
105 gp_get_text_width( Handle self, const char *text, int len, int flags);
106 
107 static Point *
108 gp_get_text_box( Handle self, const char * text, int len, int flags);
109 
110 static Bool
gp_text_out_rotated(Handle self,const char * text,uint16_t * advances,int16_t * positions,int x,int y,int len,int flags,Bool * ok_to_not_rotate)111 gp_text_out_rotated(
112 	Handle self, const char * text,
113 	uint16_t * advances, int16_t * positions,
114 	int x, int y, int len, int flags, Bool * ok_to_not_rotate
115 ) {
116 	DEFXX;
117 	int i;
118 	PRotatedFont r;
119 	XCharStruct *cs;
120 	int px, py = ( XX-> flags. paint_base_line) ?  XX-> font-> font. descent : 0;
121 	int ax = 0, ay = 0;
122 	int psx, psy, dsx, dsy;
123 	Fixed rx, ry;
124 	Bool wide = flags & toUnicode;
125 
126 	if ( !prima_update_rotated_fonts( XX-> font,
127 		text, len, wide,
128 		PDrawable( self)-> font. direction, &r, ok_to_not_rotate
129 	))
130 		return false;
131 
132 	for ( i = 0; i < len; i++) {
133 		XChar2b index;
134 		int real_ax, real_ay;
135 
136 		/* acquire actual character index */
137 		index. byte1 = wide ? (( XChar2b*) text + i)-> byte1 : 0;
138 		index. byte2 = wide ? (( XChar2b*) text + i)-> byte2 : *((unsigned char*)text + i);
139 
140 		if ( index. byte1 < r-> first1 || index. byte1 >= r-> first1 + r-> height ||
141 			index. byte2 < r-> first2 || index. byte2 >= r-> first2 + r-> width) {
142 			if ( r-> defaultChar1 < 0 || r-> defaultChar2 < 0) continue;
143 			index. byte1 = ( unsigned char) r-> defaultChar1;
144 			index. byte2 = ( unsigned char) r-> defaultChar2;
145 		}
146 
147 		/* querying character */
148 		if ( r-> map[(index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2] == NULL)
149 			continue;
150 		cs = XX-> font-> fs-> per_char ?
151 			XX-> font-> fs-> per_char +
152 				( index. byte1 - XX-> font-> fs-> min_byte1) * r-> width +
153 				index. byte2 - XX-> font-> fs-> min_char_or_byte2 :
154 			&(XX-> font-> fs-> min_bounds);
155 
156 		/* find reference point in pixmap */
157 		px = ( cs-> lbearing < 0) ? -cs-> lbearing : 0;
158 		rx. l = px * r-> cos2. l - py * r-> sin2. l + UINT16_PRECISION/2;
159 		ry. l = px * r-> sin2. l + py * r-> cos2. l + UINT16_PRECISION/2;
160 		psx = rx. i. i - r-> shift. x;
161 		psy = ry. i. i - r-> shift. y;
162 
163 		/* find glyph position */
164 		real_ax = ax;
165 		real_ay = ay;
166 		if ( positions ) {
167 			real_ax += positions[i * 2];
168 			real_ay += positions[i * 2 + 1];
169 		}
170 		rx. l = real_ax * r-> cos2. l - real_ay * r-> sin2. l + UINT16_PRECISION/2;
171 		ry. l = real_ax * r-> sin2. l + real_ay * r-> cos2. l + UINT16_PRECISION/2;
172 		dsx = x + rx. i. i - psx;
173 		dsy = REVERT( y + ry. i. i) + psy - r-> dimension. y + 1;
174 
175 		if ( guts. debug & DEBUG_FONTS) {
176 			_debug("shift %d %d\n", r-> shift.x, r-> shift.y);
177 			_debug("point ref: %d %d => %d %d. dims: %d %d, [%d %d %d]\n", px, py, psx, psy, r-> dimension.x, r-> dimension.y,
178 				cs-> lbearing, cs-> rbearing - cs-> lbearing, cs-> width - cs-> rbearing);
179 			_debug("plot ref: %d %d => %d %d\n", ax, ay, rx.i.i, ry.i.i);
180 			_debug("at: %d %d ( sz = %d), dest: %d %d\n", x, y, XX-> size.y, dsx, dsy);
181 		}
182 
183 /*   GXandReverse   ropNotDestAnd */		/* dest = (!dest) & src */
184 /*   GXorReverse    ropNotDestOr */		/* dest = (!dest) | src */
185 /*   GXequiv        ropNotSrcXor */		/* dest ^= !src */
186 /*   GXandInverted  ropNotSrcAnd */		/* dest &= !src */
187 /*   GXorInverted   ropNotSrcOr */		/* dest |= !src */
188 /*   GXnand         ropNotAnd */		/* dest = !(src & dest) */
189 /*   GXnor          ropNotOr */		/* dest = !(src | dest) */
190 /*   GXinvert       ropInvert */		/* dest = !dest */
191 
192 		switch ( XX-> paint_rop) { /* XXX Limited set edition - either expand to full list or find new way to display bitmaps */
193 		case ropXorPut:
194 			XSetBackground( DISP, XX-> gc, 0);
195 			XSetFunction( DISP, XX-> gc, GXxor);
196 			break;
197 		case ropOrPut:
198 			XSetBackground( DISP, XX-> gc, 0);
199 			XSetFunction( DISP, XX-> gc, GXor);
200 			break;
201 		case ropAndPut:
202 			XSetBackground( DISP, XX-> gc, 0xffffffff);
203 			XSetFunction( DISP, XX-> gc, GXand);
204 			break;
205 		case ropNotPut:
206 		case ropBlackness:
207 			XSetForeground( DISP, XX-> gc, 0);
208 			XSetBackground( DISP, XX-> gc, 0xffffffff);
209 			XSetFunction( DISP, XX-> gc, GXand);
210 			break;
211 		case ropWhiteness:
212 			XSetForeground( DISP, XX-> gc, 0xffffffff);
213 			XSetBackground( DISP, XX-> gc, 0);
214 			XSetFunction( DISP, XX-> gc, GXor);
215 			break;
216 		default:
217 			XSetForeground( DISP, XX-> gc, 0);
218 			XSetBackground( DISP, XX-> gc, 0xffffffff);
219 			XSetFunction( DISP, XX-> gc, GXand);
220 		}
221 		XPutImage( DISP, XX-> gdrawable, XX-> gc,
222 			r-> map[(index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2]-> image,
223 			0, 0, dsx, dsy, r-> dimension.x, r-> dimension.y);
224 		XCHECKPOINT;
225 		switch ( XX-> paint_rop) {
226 		case ropAndPut:
227 		case ropOrPut:
228 		case ropXorPut:
229 		case ropBlackness:
230 		case ropWhiteness:
231 			break;
232 		case ropNotPut:
233 			XSetForeground( DISP, XX-> gc, XX-> fore. primary);
234 			XSetBackground( DISP, XX-> gc, 0xffffffff);
235 			XSetFunction( DISP, XX-> gc, GXorInverted);
236 			goto DISPLAY;
237 		default:
238 			XSetForeground( DISP, XX-> gc, XX-> fore. primary);
239 			XSetBackground( DISP, XX-> gc, 0);
240 			XSetFunction( DISP, XX-> gc, GXor);
241 		DISPLAY:
242 			XPutImage( DISP, XX-> gdrawable, XX-> gc,
243 				r-> map[(index. byte1 - r-> first1) * r-> width + index. byte2 - r-> first2]-> image,
244 				0, 0, dsx, dsy, r-> dimension.x, r-> dimension.y);
245 			XCHECKPOINT;
246 		}
247 		ax += advances ? advances[i] : cs-> width;
248 	}
249 	apc_gp_set_rop( self, XX-> paint_rop);
250 	XSetFillStyle( DISP, XX-> gc, FillSolid);
251 	XSetForeground( DISP, XX-> gc, XX-> fore. primary);
252 	XSetBackground( DISP, XX-> gc, XX-> back. primary);
253 	XX-> flags. brush_fore = 1;
254 	XX-> flags. brush_back = 1;
255 
256 	if ( PDrawable( self)-> font. style & (fsUnderlined|fsStruckOut)) {
257 		int lw = apc_gp_get_line_width( self);
258 		int tw = gp_get_text_width( self, text, len, flags | toAddOverhangs) - 1;
259 		int d  = XX-> font-> underlinePos;
260 		Point ovx = gp_get_text_overhangs( self, text, len, flags);
261 		int x1, y1, x2, y2;
262 		if ( lw != XX-> font-> underlineThickness)
263 			apc_gp_set_line_width( self, XX-> font-> underlineThickness);
264 
265 		if ( PDrawable( self)-> font. style & fsUnderlined) {
266 			ay = d + ( XX-> flags. paint_base_line ? 0 : XX-> font-> font. descent);
267 			rx. l = -ovx.x * r-> cos2. l - ay * r-> sin2. l + 0.5;
268 			ry. l = -ovx.x * r-> sin2. l + ay * r-> cos2. l + 0.5;
269 			x1 = x + rx. i. i;
270 			y1 = y + ry. i. i;
271 			tw += ovx.y;
272 			rx. l = tw * r-> cos2. l - ay * r-> sin2. l + 0.5;
273 			ry. l = tw * r-> sin2. l + ay * r-> cos2. l + 0.5;
274 			x2 = x + rx. i. i;
275 			y2 = y + ry. i. i;
276 			XDrawLine( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y1), x2, REVERT( y2));
277 		}
278 
279 		if ( PDrawable( self)-> font. style & fsStruckOut) {
280 			ay = (PDrawable( self)-> font.ascent - PDrawable( self)-> font.internalLeading)/2 +
281 				+ ( XX-> flags. paint_base_line ? 0 : XX-> font-> font. descent);
282 			rx. l = -ovx.x * r-> cos2. l - ay * r-> sin2. l + 0.5;
283 			ry. l = -ovx.x * r-> sin2. l + ay * r-> cos2. l + 0.5;
284 			x1 = x + rx. i. i;
285 			y1 = y + ry. i. i;
286 			tw += ovx.y;
287 			rx. l = tw * r-> cos2. l - ay * r-> sin2. l + 0.5;
288 			ry. l = tw * r-> sin2. l + ay * r-> cos2. l + 0.5;
289 			x2 = x + rx. i. i;
290 			y2 = y + ry. i. i;
291 			XDrawLine( DISP, XX-> gdrawable, XX-> gc, x1, REVERT( y1), x2, REVERT( y2));
292 		}
293 
294 		if ( lw != XX-> font-> underlineThickness)
295 			apc_gp_set_line_width( self, lw);
296 	}
297 	XFLUSH;
298 	return true;
299 }
300 
301 static void
paint_text_background(Handle self,const char * text,int x,int y,int len,int flags)302 paint_text_background( Handle self, const char * text, int x, int y, int len, int flags)
303 {
304 	DEFXX;
305 	int i;
306 	Point * p;
307 	FillPattern fp;
308 
309 	memcpy( &fp, apc_gp_get_fill_pattern( self), sizeof( FillPattern));
310 	p = gp_get_text_box( self, text, len, flags);
311 	XSetForeground( DISP, XX-> gc, XX-> back. primary);
312 	XX-> flags. brush_back = 0;
313 	XX-> flags. brush_fore = 1;
314 	XX-> fore. balance = 0;
315 	XSetFunction( DISP, XX-> gc, GXcopy);
316 	apc_gp_set_fill_pattern( self, fillPatterns[fpSolid]);
317 	for ( i = 0; i < 4; i++) {
318 		p[i].x += x;
319 		p[i].y += y;
320 	}
321 	i = p[2].x; p[2].x = p[3].x; p[3].x = i;
322 	i = p[2].y; p[2].y = p[3].y; p[3].y = i;
323 
324 	apc_gp_fill_poly( self, 4, p);
325 	apc_gp_set_rop( self, XX-> paint_rop);
326 	apc_gp_set_color( self, XX-> fore. color);
327 	apc_gp_set_fill_pattern( self, fp);
328 	free( p);
329 }
330 
331 static void
draw_text_underline(Handle self,const char * text,int x,int y,int len,int flags)332 draw_text_underline(Handle self, const char * text, int x, int y, int len, int flags)
333 {
334 	DEFXX;
335 	int lw = apc_gp_get_line_width( self) + .5;
336 	int tw = gp_get_text_width( self, text, len, flags | toAddOverhangs);
337 	int d  = XX-> font-> underlinePos;
338 	Point ovx = gp_get_text_overhangs( self, text, len, flags);
339 	if ( lw != XX-> font-> underlineThickness)
340 		apc_gp_set_line_width( self, XX-> font-> underlineThickness);
341 	if ( PDrawable( self)-> font. style & fsUnderlined)
342 		XDrawLine( DISP, XX-> gdrawable, XX-> gc,
343 			x - ovx.x, REVERT( y + d), x + tw - 1 + ovx.y, REVERT( y + d));
344 	if ( PDrawable( self)-> font. style & fsStruckOut) {
345 		int scy = REVERT( y + (XX-> font-> font.ascent - XX-> font-> font.internalLeading)/2);
346 		XDrawLine( DISP, XX-> gdrawable, XX-> gc,
347 			x - ovx.x, scy, x + tw - 1 + ovx.y, scy);
348 	}
349 	if ( lw != XX-> font-> underlineThickness)
350 		apc_gp_set_line_width( self, lw);
351 }
352 
353 static Bool
text_out(Handle self,const char * text,int x,int y,int len,int flags)354 text_out( Handle self, const char * text, int x, int y, int len, int flags)
355 {
356 	DEFXX;
357 	if ( !XX-> flags. paint_base_line)
358 		y += XX-> font-> font. descent;
359 
360 	XSetFillStyle( DISP, XX-> gc, FillSolid);
361 	if ( !XX-> flags. brush_fore) {
362 		XSetForeground( DISP, XX-> gc, XX-> fore. primary);
363 		XX-> flags. brush_fore = 1;
364 	}
365 
366 	if ( flags & toUTF8)
367 		XDrawString16( DISP, XX-> gdrawable, XX-> gc, x, REVERT( y) + 1, (XChar2b*) text, len);
368 	else
369 		XDrawString( DISP, XX-> gdrawable, XX-> gc, x, REVERT( y) + 1, ( char*) text, len);
370 	XCHECKPOINT;
371 	return true;
372 }
373 
374 static Bool
glyphs_out_with_advances(Handle self,PGlyphsOutRec t,int x,int y)375 glyphs_out_with_advances( Handle self, PGlyphsOutRec t, int x, int y)
376 {
377 	DEFXX;
378 	int i, run_length, next_x;
379 	uint16_t * glyphs, *advances, *run_glyphs;
380 	int16_t * positions;
381 	CharStructABC s;
382 	if ( !XX-> flags. paint_base_line)
383 		y += XX-> font-> font. descent;
384 
385 	XSetFillStyle( DISP, XX-> gc, FillSolid);
386 	if ( !XX-> flags. brush_fore) {
387 		XSetForeground( DISP, XX-> gc, XX-> fore. primary);
388 		XX-> flags. brush_fore = 1;
389 	}
390 
391 	init_xchar_abc(XX->font->fs, &s);
392 	y = REVERT(y) + 1;
393 	next_x = x;
394 	for (
395 		i = run_length = 0,
396 			glyphs = run_glyphs = t-> glyphs,
397 			advances = t-> advances,
398 			positions = t->positions;
399 		i < t-> len;
400 		i++, glyphs++, advances++, positions += 2
401 	) {
402 		uint16_t xc = *glyphs;
403 		int default_advance;
404 
405 		SWAP_BYTES(&xc, 1);
406 		default_advance = xchar_struct(&s, xc)-> width;
407 
408 		if (
409 			(positions[0] == 0 && positions[1] == 0) &&
410 			(default_advance == *advances || i == t->len-1)
411 		) {
412 			run_length++;
413 			next_x += default_advance;
414 		} else {
415 			if ( run_length > 0 ) {
416 				XDrawString16( DISP, XX-> gdrawable, XX-> gc,
417 					x, y, (XChar2b*) run_glyphs, run_length);
418 				x = next_x;
419 			}
420 			XDrawString16( DISP, XX-> gdrawable, XX-> gc,
421 				x + positions[0], y - positions[1], (XChar2b*) glyphs, 1);
422 			next_x += *advances;
423 			run_glyphs = glyphs + 1;
424 			run_length = 0;
425 			x = next_x;
426 		}
427 	}
428 	if ( run_length > 0 )
429 		XDrawString16( DISP, XX-> gdrawable, XX-> gc,
430 			x, y, (XChar2b*) run_glyphs, run_length);
431 
432 	XCHECKPOINT;
433 	return true;
434 }
435 
436 Bool
apc_gp_text_out(Handle self,const char * text,int x,int y,int len,int flags)437 apc_gp_text_out( Handle self, const char * text, int x, int y, int len, int flags)
438 {
439 	Bool ret;
440 	DEFXX;
441 
442 	if ( PObject( self)-> options. optInDrawInfo) return false;
443 	if ( !XF_IN_PAINT(XX)) return false;
444 
445 	if ( len == 0) return true;
446 	if ( len > 65535 ) len = 65535;
447 	flags &= ~toGlyphs;
448 
449 #ifdef USE_XFT
450 	if ( XX-> font-> xft)
451 		return prima_xft_text_out( self, text, x, y, len, flags);
452 #endif
453 
454 	if ( flags & toUTF8 )
455 		if ( !( text = ( char *) prima_alloc_utf8_to_wchar( text, len))) return false;
456 
457 	if ( XX-> flags. paint_opaque)
458 		paint_text_background( self, text, x, y, len, flags);
459 
460 	SHIFT(x, y);
461 	RANGE2(x,y);
462 	if ( PDrawable( self)-> font. direction != 0) {
463 		Bool ok_to_not_rotate = false;
464 		Bool ret;
465 		ret = gp_text_out_rotated( self, text, NULL, NULL, x, y, len, flags, &ok_to_not_rotate);
466 		if ( !ok_to_not_rotate) {
467 			if ( flags & toUTF8) free(( char *) text);
468 			return ret;
469 		}
470 	}
471 
472 	ret = text_out(self, text, x, y, len, flags);
473 	if ( PDrawable( self)-> font. style & (fsUnderlined|fsStruckOut))
474 		draw_text_underline(self, text, x, y, len, flags);
475 
476 	if ( flags & toUTF8) free(( char *) text);
477 	XFLUSH;
478 
479 	return ret;
480 }
481 
482 Bool
apc_gp_glyphs_out(Handle self,PGlyphsOutRec t,int x,int y)483 apc_gp_glyphs_out( Handle self, PGlyphsOutRec t, int x, int y)
484 {
485 	Bool ret;
486 	DEFXX;
487 
488 	if ( PObject( self)-> options. optInDrawInfo) return false;
489 	if ( !XF_IN_PAINT(XX)) return false;
490 
491 	if ( t->len == 0) return true;
492 	if ( t->len > 65535 ) t->len = 65535;
493 
494 #ifdef USE_XFT
495 	if ( XX-> font-> xft)
496 		return prima_xft_glyphs_out( self, t, x, y);
497 #endif
498 
499 	SWAP_BYTES(t->glyphs,t->len);
500 	if ( XX-> flags. paint_opaque)
501 		paint_text_background( self, (const char*) t->glyphs, x, y, t->len, toUnicode);
502 
503 	SHIFT(x, y);
504 	RANGE2(x,y);
505 	if ( PDrawable( self)-> font. direction != 0) {
506 		Bool ok_to_not_rotate = false;
507 		ret = gp_text_out_rotated( self, (const char*) t->glyphs,
508 			t->advances, t->positions,
509 			x, y, t->len, toUnicode, &ok_to_not_rotate);
510 		if ( !ok_to_not_rotate)
511 			goto EXIT;
512 	}
513 
514 	ret =
515 		t-> advances ?
516 		glyphs_out_with_advances(self, t, x, y) :
517 		text_out(self, (const char*) t->glyphs, x, y, t->len, toUnicode);
518 
519 	if ( PDrawable( self)-> font. style & (fsUnderlined|fsStruckOut))
520 		draw_text_underline(self, (const char*) t->glyphs, x, y, t->len, toUnicode);
521 	XFLUSH;
522 
523 EXIT:
524 	SWAP_BYTES(t->glyphs,t->len);
525 	return ret;
526 }
527 
528 Bool
text_shaper_core_text(Handle self,PTextShapeRec r)529 text_shaper_core_text( Handle self, PTextShapeRec r)
530 {
531         int i;
532 	uint16_t *glyphs;
533 	uint32_t *text;
534 
535         for ( i = 0, glyphs = r->glyphs, text = r->text; i < r->len; i++) {
536                 uint32_t c = *(text++);
537                 if ( c > 0xffff ) c = 0x0;
538                 *(glyphs++) = c;
539         }
540         r-> n_glyphs = r->len;
541 
542 	if ( r-> advances ) {
543 		uint16_t *glyphs, *advances;
544 		CharStructABC s;
545 		init_xchar_abc(X(self)->font->fs, &s);
546 		for (
547 			i = 0, glyphs = r->glyphs, advances = r->advances;
548 			i < r-> len;
549 			i++
550 		)
551 			*(advances++) = xchar_struct(&s, *(glyphs++))-> width;
552 		bzero(r->positions, r->len * 2 * sizeof(int16_t));
553 	}
554 
555 	return true;
556 }
557 
558 PTextShapeFunc
apc_gp_get_text_shaper(Handle self,int * type)559 apc_gp_get_text_shaper( Handle self, int * type)
560 {
561 #ifdef USE_XFT
562 	if ( X(self)-> font && X(self)-> font-> xft) {
563 		int t = *type;
564 #ifdef WITH_HARFBUZZ
565 		if ( guts. use_harfbuzz && *type == tsFull )
566 			return prima_xft_text_shaper_harfbuzz;
567 #endif
568 		*type = tsGlyphs;
569 		return ( t == tsBytes ) ?
570 			prima_xft_text_shaper_bytes :
571 			prima_xft_text_shaper_ident;
572 	}
573 #endif
574 	*type = tsNone;
575 	return text_shaper_core_text;
576 }
577 
578 PFontABC
prima_xfont2abc(XFontStruct * fs,int firstChar,int lastChar)579 prima_xfont2abc( XFontStruct * fs, int firstChar, int lastChar)
580 {
581 	int k, l;
582 	CharStructABC s;
583 	PFontABC abc = malloc( sizeof( FontABC) * (lastChar - firstChar + 1));
584 	init_xchar_abc(fs, &s);
585 	for ( k = firstChar, l = 0; k <= lastChar; k++, l++) {
586 		XCharStruct * cs = xchar_struct(&s, (unsigned int) k);
587 		abc[l]. a = cs-> lbearing;
588 		abc[l]. b = cs-> rbearing - cs-> lbearing;
589 		abc[l]. c = cs-> width - cs-> rbearing;
590 	}
591 	return abc;
592 }
593 
594 PFontABC
apc_gp_get_font_abc(Handle self,int firstChar,int lastChar,int flags)595 apc_gp_get_font_abc( Handle self, int firstChar, int lastChar, int flags)
596 {
597 	PFontABC abc;
598 
599 	if ( self) {
600 		DEFXX;
601 #ifdef USE_XFT
602 		if ( XX-> font-> xft)
603 			return prima_xft_get_font_abc( self, firstChar, lastChar, flags);
604 #endif
605 
606 		abc = prima_xfont2abc( XX-> font-> fs, firstChar, lastChar);
607 	} else
608 		abc = prima_xfont2abc( guts. font_abc_nil_hack, firstChar, lastChar);
609 	return abc;
610 }
611 
612 PFontABC
prima_xfont2def(Handle self,int first,int last)613 prima_xfont2def( Handle self, int first, int last)
614 {
615 	DEFXX;
616 	XCharStruct *max;
617 	Pixmap pixmap;
618 	GC gc;
619 	XGCValues gcv;
620 	int i, j, k, w, h, ls;
621 	PFontABC ret;
622 	XImage *xi;
623 
624 	if ( !( ret = malloc( sizeof(FontABC) * ( last - first + 1 ) )))
625 		return NULL;
626 	bzero( ret, sizeof(FontABC) * ( last - first + 1 ));
627 
628 	max = &XX-> font-> fs-> max_bounds;
629 	w  = max-> width * 3;
630 	h  = max-> descent + max-> ascent;
631 	ls = (( w + 31) / 32) * 4;
632 	w  = ls * 8;
633 	pixmap = XCreatePixmap( DISP, guts. root, w, h, 1);
634 	gcv. graphics_exposures = false;
635 	gc = XCreateGC( DISP, pixmap, GCGraphicsExposures, &gcv);
636 	XSetFont( DISP, gc, XX-> font-> id);
637 
638 	for ( i = 0; i <= last - first; i++) {
639 		XChar2b ch;
640 		ch. byte1 = (first + i) / 256;
641 		ch. byte2 = (first + i) % 256;
642 		XSetForeground( DISP, gc, 0);
643 		XFillRectangle( DISP, pixmap, gc, 0, 0, w, h);
644 		XSetForeground( DISP, gc, 1);
645 		XDrawString16( DISP, pixmap, gc, 10, h - XX->font->font. descent, &ch, 1);
646 
647 		if (!(xi = XGetImage( DISP, pixmap, 0, 0, w, h, 1, XYPixmap))) {
648 			free( ret );
649 			ret = NULL;
650 			break;
651 		}
652 		/*
653 		for ( j = 0; j < h; j++) {
654 			int k, l;
655 			for ( k = 0; k < ls; k++) {
656 				Byte * p = (Byte*)xi-> data + j * xi-> bytes_per_line + k;
657 				printf(".");
658 				for ( l = 0; l < 8; l++) {
659 					int z = (*p) & ( 1 << l );
660 					printf("%s", z ? "*" : " ");
661 				}
662 			}
663 			printf("\n");
664 		}
665 		*/
666 		for ( j = 0; j < h; j++) {
667 			Byte * p = (Byte*)xi-> data + j * xi-> bytes_per_line;
668 			for ( k = 0; k < ls; k++, p++) {
669 				if ( *p != 0 ) {
670 					ret[i]. c = j;
671 					goto FOUND_C;
672 				}
673 			}
674 		}
675 		FOUND_C:
676 		for ( j = h - 1; j >= 0; j--) {
677 			Byte * p = (Byte*)xi-> data + j * xi-> bytes_per_line;
678 			for ( k = 0; k < ls; k++, p++) {
679 				if ( *p != 0 ) {
680 					ret[i]. a = h - j - 1;
681 					goto FOUND_A;
682 				}
683 			}
684 		}
685 		FOUND_A:
686 		if ( ret[i].a != 0 || ret[i].c != 0)
687 			ret[i]. b = h - ret[i]. a - ret[i]. c;
688 		XDestroyImage( xi);
689 	}
690 
691 	XFreeGC( DISP, gc);
692 	XFreePixmap( DISP, pixmap);
693 
694 	return ret;
695 }
696 
697 PFontABC
apc_gp_get_font_def(Handle self,int firstChar,int lastChar,int flags)698 apc_gp_get_font_def( Handle self, int firstChar, int lastChar, int flags)
699 {
700 	PFontABC abc;
701 #ifdef USE_XFT
702 	DEFXX;
703 	if ( XX-> font-> xft)
704 		return prima_xft_get_font_def( self, firstChar, lastChar, flags);
705 #endif
706 	abc = prima_xfont2def( self, firstChar, lastChar);
707 	return abc;
708 }
709 
710 static int
gp_get_text_width(Handle self,const char * text,int len,int flags)711 gp_get_text_width( Handle self, const char *text, int len, int flags)
712 {
713 	DEFXX;
714 	int ret;
715 	ret = (flags & toUTF8) ?
716 		XTextWidth16( XX-> font-> fs, ( XChar2b *) text, len) :
717 		XTextWidth  ( XX-> font-> fs, (char*) text, len);
718 	if ( flags & toAddOverhangs ) {
719 		Point ovx = gp_get_text_overhangs( self, text, len, flags);
720 		ret += ovx. x + ovx. y;
721 	}
722 	return ret;
723 }
724 
725 int
apc_gp_get_text_width(Handle self,const char * text,int len,int flags)726 apc_gp_get_text_width( Handle self, const char * text, int len, int flags)
727 {
728 	int ret;
729 
730 	flags &= ~toGlyphs;
731 	if ( len > 65535 ) len = 65535;
732 
733 #ifdef USE_XFT
734 	if ( X(self)-> font-> xft)
735 		return prima_xft_get_text_width( X(self)-> font, text, len, flags,
736 			X(self)-> xft_map8, NULL);
737 #endif
738 
739 	if ( flags & toUTF8 )
740 		if ( !( text = ( char *) prima_alloc_utf8_to_wchar( text, len))) return 0;
741 	ret = gp_get_text_width( self, text, len, flags);
742 	if ( flags & toUTF8)
743 		free(( char*) text);
744 	return ret;
745 }
746 
747 int
apc_gp_get_glyphs_width(Handle self,PGlyphsOutRec t)748 apc_gp_get_glyphs_width( Handle self, PGlyphsOutRec t)
749 {
750 	int ret;
751 	if ( t->len > 65535 ) t->len = 65535;
752 
753 #ifdef USE_XFT
754 	if ( X(self)-> font-> xft)
755 		return prima_xft_get_glyphs_width( X(self)-> font, t, NULL);
756 #endif
757 
758 	SWAP_BYTES(t->glyphs,t->len);
759 	ret = gp_get_text_width( self, (char*) t->glyphs, t->len, toUTF8 );
760 	SWAP_BYTES(t->glyphs,t->len);
761 	return ret;
762 }
763 
764 static Point *
gp_get_text_box(Handle self,const char * text,int len,int flags)765 gp_get_text_box( Handle self, const char * text, int len, int flags)
766 {
767 	DEFXX;
768 	Point * pt = ( Point *) malloc( sizeof( Point) * 5);
769 	int x;
770 	Point ovx;
771 
772 	if ( !pt) return NULL;
773 	if ( flags & toGlyphs ) flags &= ~toUTF8;
774 
775 	x = (flags & toUTF8) ?
776 		XTextWidth16( XX-> font-> fs, ( XChar2b*) text, len) :
777 		XTextWidth( XX-> font-> fs, (char*)text, len);
778 	ovx = gp_get_text_overhangs( self, text, len, flags);
779 
780 	pt[0].y = pt[2]. y = XX-> font-> font. ascent - 1;
781 	pt[1].y = pt[3]. y = - XX-> font-> font. descent;
782 	pt[4].y = 0;
783 	pt[4].x = x;
784 	pt[3].x = pt[2]. x = x + ovx. y;
785 	pt[0].x = pt[1]. x = - ovx. x;
786 
787 	if ( !XX-> flags. paint_base_line) {
788 		int i;
789 		for ( i = 0; i < 4; i++) pt[i]. y += XX-> font-> font. descent;
790 	}
791 
792 	if ( PDrawable( self)-> font. direction != 0) {
793 		int i;
794 		double s = sin( PDrawable( self)-> font. direction / 57.29577951);
795 		double c = cos( PDrawable( self)-> font. direction / 57.29577951);
796 		for ( i = 0; i < 5; i++) {
797 			double x = pt[i]. x * c - pt[i]. y * s;
798 			double y = pt[i]. x * s + pt[i]. y * c;
799 			pt[i]. x = x + (( x > 0) ? 0.5 : -0.5);
800 			pt[i]. y = y + (( y > 0) ? 0.5 : -0.5);
801 		}
802 	}
803 
804 	return pt;
805 }
806 
807 Point *
apc_gp_get_text_box(Handle self,const char * text,int len,int flags)808 apc_gp_get_text_box( Handle self, const char * text, int len, int flags)
809 {
810 	Point * ret;
811 
812 	if ( len > 65535 ) len = 65535;
813 
814 #ifdef USE_XFT
815 	if ( X(self)-> font-> xft)
816 		return prima_xft_get_text_box( self, text, len, flags);
817 #endif
818 	if ( flags & toUTF8)
819 		if ( !( text = ( char *) prima_alloc_utf8_to_wchar( text, len))) return 0;
820 	ret = gp_get_text_box( self, text, len, flags);
821 	if ( flags & toUTF8)
822 		free(( char*) text);
823 	return ret;
824 }
825 
826 Point *
apc_gp_get_glyphs_box(Handle self,PGlyphsOutRec t)827 apc_gp_get_glyphs_box( Handle self, PGlyphsOutRec t)
828 {
829 	Point * ret;
830 	if ( t->len > 65535 ) t->len = 65535;
831 #ifdef USE_XFT
832 	if ( X(self)-> font-> xft)
833 		return prima_xft_get_glyphs_box( self, t);
834 #endif
835 	SWAP_BYTES(t->glyphs,t->len);
836 	ret = gp_get_text_box( self, (char*) t->glyphs, t->len, toUTF8);
837 	SWAP_BYTES(t->glyphs,t->len);
838 	return ret;
839 }
840 
841