1/*
2
3Copyright 1990, 1991, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25 * Copyright 1990, 1991 Network Computing Devices;
26 * Portions Copyright 1987 by Digital Equipment Corporation
27 *
28 * Permission to use, copy, modify, distribute, and sell this software and
29 * its documentation for any purpose is hereby granted without fee, provided
30 * that the above copyright notice appear in all copies and that both that
31 * copyright notice and this permission notice appear in supporting
32 * documentation, and that the names of Network Computing Devices, or Digital
33 * not be used in advertising or publicity pertaining to distribution
34 * of the software without specific, written prior permission.
35 *
36 * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
37 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
38 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES,
39 * OR DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
40 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
41 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
42 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
43 * THIS SOFTWARE.
44 */
45/*
46 * Defines GetExtents() and GetBitmaps(), which are
47 * called from routines in fontinfo.c.
48 * This file was once on the other side of
49 * the font library interface as util/fsfuncs.c.
50 */
51
52#include "config.h"
53
54#include <X11/Xos.h>
55#include "misc.h"
56#include <X11/fonts/fontstruct.h>
57
58#include "clientstr.h"
59#define FSMD_H
60#include <X11/fonts/FSproto.h>
61#include "difs.h"
62
63#define GLWIDTHBYTESPADDED(bits,nbytes) \
64	((nbytes) == 1 ? (((bits)+7)>>3)        /* pad to 1 byte */ \
65	:(nbytes) == 2 ? ((((bits)+15)>>3)&~1)  /* pad to 2 bytes */ \
66	:(nbytes) == 4 ? ((((bits)+31)>>3)&~3)  /* pad to 4 bytes */ \
67	:(nbytes) == 8 ? ((((bits)+63)>>3)&~7)  /* pad to 8 bytes */ \
68	: 0)
69
70#define GLYPH_SIZE(ch, nbytes)          \
71	GLWIDTHBYTESPADDED((ch)->metrics.rightSideBearing - \
72			(ch)->metrics.leftSideBearing, (nbytes))
73
74#define n2dChars(pfi)   (((pfi)->lastRow - (pfi)->firstRow + 1) * \
75                         ((pfi)->lastCol - (pfi)->firstCol + 1))
76
77#if 0
78static CharInfoRec  junkDefault;
79#endif
80
81typedef int (*MetricsFunc)(FontPtr, unsigned long, unsigned char *,
82			   FontEncoding, unsigned long *, CharInfoPtr *);
83
84static int
85getCharInfos (
86    FontPtr	pfont,
87    int		num_ranges,
88    fsRange	*range,
89    Bool	ink_metrics,
90    int		*nump,		/* return */
91    CharInfoPtr	**retp)		/* return */
92{
93    CharInfoPtr	*xchars, *xci;
94    int		nchars;
95    FontInfoPtr pinfo = &pfont->info;
96    unsigned int r, c;
97    unsigned char   ch[2];
98    int         firstCol = pinfo->firstCol;
99    int         firstRow = pinfo->firstRow;
100    int         lastRow = pinfo->lastRow;
101    int         lastCol = pinfo->lastCol;
102    fsRange	local_range, *rp;
103    int		i;
104    FontEncoding    encoding;
105    int		err;
106    unsigned long   glyphCount;
107    unsigned short  defaultCh;
108    CharInfoPtr	    defaultPtr;
109    MetricsFunc	    metrics_func;
110
111    /*
112     * compute nchars
113     */
114    if (num_ranges == 0) {
115	if (lastRow)
116	    nchars = n2dChars(pinfo);
117	else
118	    nchars = lastCol - firstCol + 1;
119	local_range.min_char_low = firstCol;
120	local_range.min_char_high = firstRow;
121	local_range.max_char_low = lastCol;
122	local_range.max_char_high = lastRow;
123	range = &local_range;
124	num_ranges = 1;
125    } else {
126	nchars = 0;
127	for (i = 0, rp = range; i < num_ranges; i++, rp++) {
128	    if (rp->min_char_high > rp->max_char_high ||
129		rp->min_char_low > rp->max_char_low)
130		return BadCharRange;
131	    nchars += (rp->max_char_high - rp->min_char_high + 1) *
132		      (rp->max_char_low - rp->min_char_low + 1);
133	}
134    }
135
136    xchars = (CharInfoPtr *) FScalloc (nchars, sizeof (CharInfoPtr));
137    if (!xchars)
138	return AllocError;
139
140    if (ink_metrics)
141	metrics_func = (MetricsFunc)pfont->get_metrics;
142    else
143	metrics_func = pfont->get_glyphs;
144
145    xci = xchars;
146    encoding = Linear16Bit;
147    if (lastRow)
148	encoding = TwoD16Bit;
149    defaultCh = pinfo->defaultCh;
150    ch[0] = defaultCh >> 8;
151    ch[1] = defaultCh & 0xff;
152    /* get the default character */
153    (*metrics_func) (pfont, 1, ch, encoding,
154			  &glyphCount, &defaultPtr);
155    if (glyphCount != 1)
156	defaultPtr = NULL;
157
158    /* for each range, get each character individually, undoing the
159     default character substitution so we get zero metrics for
160     non-existent characters. */
161    for (i = 0, rp = range; i < num_ranges; i++, rp++) {
162	for (r = rp->min_char_high; r <= rp->max_char_high; r++)
163	{
164	    for (c = rp->min_char_low; c <= rp->max_char_low; c++) {
165		ch[0] = r;
166		ch[1] = c;
167		err = (*metrics_func) (pfont, 1, ch, encoding,
168					    &glyphCount, xci);
169		if (err != Successful)
170		{
171		    FSfree (xchars);
172		    return err;
173		}
174#if 0
175		if (glyphCount != 1 ||
176		   (*xci == defaultPtr && defaultCh != ((r<<8)+c)))
177		    *xci = &junkDefault;
178#endif
179		xci++;
180	    }
181	}
182    }
183    *retp = xchars;
184    *nump = nchars;
185    return Successful;
186}
187
188int
189GetExtents(
190    ClientPtr   client,
191    FontPtr     pfont,
192    Mask        flags,
193    unsigned long num_ranges,
194    fsRange    *range,
195    unsigned long *num_extents,	/* return */
196    fsXCharInfo **data)		/* return */
197{
198    fsXCharInfo *ci;
199    fsXCharInfo cilocal;
200    char *pci;
201    CharInfoPtr	*xchars, *xchars_cur;
202    CharInfoPtr xci;
203    int		nchars;
204    int		err;
205
206    if (flags & LoadAll)
207	num_ranges = 0;
208    err = getCharInfos (pfont, num_ranges, range,
209			client->major_version > 1 ? TRUE : FALSE,
210			&nchars, &xchars);
211    if (err != Successful)
212	return err;
213
214    pci = (char *) FSallocarray(nchars, SIZEOF(fsXCharInfo));
215    if (!pci) {
216	FSfree (xchars);
217	return AllocError;
218    }
219
220    ci = (fsXCharInfo *) pci;
221    *num_extents = nchars;
222
223    /* pack the data */
224    xchars_cur = xchars;
225    while (nchars--) {
226	xci = *xchars_cur++;
227	cilocal.ascent = xci->metrics.ascent;
228	cilocal.descent = xci->metrics.descent;
229	cilocal.left = xci->metrics.leftSideBearing;
230	cilocal.right = xci->metrics.rightSideBearing;
231	cilocal.width = xci->metrics.characterWidth;
232	cilocal.attributes = xci->metrics.attributes;
233	memcpy(pci, &cilocal, SIZEOF(fsXCharInfo));
234	pci += SIZEOF(fsXCharInfo);
235    }
236
237    FSfree (xchars);
238
239    *data = ci;
240
241    return Successful;
242}
243
244static int
245CheckFSFormat(fsBitmapFormat format,
246	      fsBitmapFormatMask fmask,
247	      int *bit_order,
248	      int *byte_order,
249	      int *scan,
250	      int *glyph,
251	      int *image)
252{
253    /* convert format to what the low levels want */
254    if (fmask & BitmapFormatMaskBit) {
255	*bit_order = format & BitmapFormatBitOrderMask;
256	*bit_order = (*bit_order == BitmapFormatBitOrderMSB)
257	    	     ? MSBFirst : LSBFirst;
258    }
259    if (fmask & BitmapFormatMaskByte) {
260	*byte_order = format & BitmapFormatByteOrderMask;
261	*byte_order = (*byte_order == BitmapFormatByteOrderMSB)
262	    	      ? MSBFirst : LSBFirst;
263    }
264    if (fmask & BitmapFormatMaskScanLineUnit) {
265	*scan = format & BitmapFormatScanlineUnitMask;
266	/* convert byte paddings into byte counts */
267	switch (*scan) {
268	case BitmapFormatScanlineUnit8:
269	    *scan = 1;
270	    break;
271	case BitmapFormatScanlineUnit16:
272	    *scan = 2;
273	    break;
274	case BitmapFormatScanlineUnit32:
275	    *scan = 4;
276	    break;
277	default:
278	    return BadFontFormat;
279	}
280    }
281    if (fmask & BitmapFormatMaskScanLinePad) {
282	*glyph = format & BitmapFormatScanlinePadMask;
283	/* convert byte paddings into byte counts */
284	switch (*glyph) {
285	case BitmapFormatScanlinePad8:
286	    *glyph = 1;
287	    break;
288	case BitmapFormatScanlinePad16:
289	    *glyph = 2;
290	    break;
291	case BitmapFormatScanlinePad32:
292	    *glyph = 4;
293	    break;
294	default:
295	    return BadFontFormat;
296	}
297    }
298    if (fmask & BitmapFormatMaskImageRectangle) {
299	*image = format & BitmapFormatImageRectMask;
300
301	if (*image != BitmapFormatImageRectMin &&
302		*image != BitmapFormatImageRectMaxWidth &&
303		*image != BitmapFormatImageRectMax)
304	    return BadFontFormat;
305    }
306    return Successful;
307}
308
309static int
310packGlyphs (
311    ClientPtr   client,
312    FontPtr     pfont,
313    int         format,
314    Mask        flags,
315    unsigned long num_ranges,
316    fsRange    *range,
317    int        *tsize,
318    unsigned long *num_glyphs,
319    fsOffset32  **offsets,
320    pointer     *data,
321    int		*freeData)
322{
323    int         i;
324    fsOffset32	*lengths, *l;
325    unsigned long size = 0;
326    pointer     gdata;
327    unsigned char *gd;
328    int         bitorder, byteorder, scanlinepad, scanlineunit, mappad;
329    int		height = 0, dstbpr = 0, charsize = 0;
330    int		dst_off = 0, src_off;
331    Bool	contiguous, reformat;
332    int		nchars;
333    int         src_glyph_pad = pfont->glyph;
334    int         src_bit_order = pfont->bit;
335    int         src_byte_order = pfont->byte;
336    int         err;
337    int		max_ascent = 0, max_descent = 0;
338    int		min_left = 0, max_right;
339    int		srcbpr;
340    int		lshift = 0, rshift = 0, dst_left_bytes = 0, src_left_bytes = 0;
341    unsigned char   *srcp;
342    unsigned char   *dstp;
343    unsigned char   bits1, bits2;
344    int		    width;
345    int		    src_extra;
346    int		    dst_extra;
347    int		    r, w;
348    CharInfoPtr	*bitChars, *bitCharsFree, bitc;
349    CharInfoPtr	*inkChars, *inkCharsFree = NULL, inkc;
350    FontInfoPtr	pinfo = &pfont->info;
351    xCharInfo	*bitm, *inkm;
352
353    err = CheckFSFormat(format, (fsBitmapFormatMask) ~ 0,
354			&bitorder, &byteorder, &scanlineunit, &scanlinepad, &mappad);
355
356    if (err != Successful)
357	return err;
358
359    if (flags & LoadAll)
360	num_ranges = 0;
361
362    err = getCharInfos (pfont, num_ranges, range, FALSE, &nchars, &bitCharsFree);
363
364    if (err != Successful)
365	return err;
366
367    /* compute dstbpr for padded out fonts */
368    reformat = bitorder != src_bit_order || byteorder != src_byte_order;
369
370    /* we need the ink metrics when shrink-wrapping a TE font (sigh),
371     * but only for protocol version > 1 */
372    if (mappad != BitmapFormatImageRectMax &&
373	pinfo->inkMetrics &&
374	client->major_version > 1)
375    {
376	err = getCharInfos (pfont, num_ranges, range, TRUE, &nchars, &inkCharsFree);
377	if (err != Successful)
378	{
379	    FSfree (bitCharsFree);
380	    return err;
381	}
382	reformat = TRUE;
383    }
384
385    /* get space for glyph offsets */
386    lengths = (fsOffset32 *) FSallocarray(nchars, SIZEOF(fsOffset32));
387    if (!lengths) {
388	FSfree (bitCharsFree);
389	FSfree (inkCharsFree);
390	return AllocError;
391    }
392
393    switch (mappad)
394    {
395    case BitmapFormatImageRectMax:
396	max_ascent = FONT_MAX_ASCENT(pinfo);
397	max_descent = FONT_MAX_DESCENT(pinfo);
398	height = max_ascent + max_descent;
399	/* do font ascent and font descent match bitmap bounds ? */
400	if (height != pinfo->minbounds.ascent + pinfo->minbounds.descent)
401	    reformat = TRUE;
402	/* fall through */
403    case BitmapFormatImageRectMaxWidth:
404	min_left = FONT_MIN_LEFT(pinfo);
405	max_right = FONT_MAX_RIGHT(pinfo);
406	if (min_left != pinfo->maxbounds.leftSideBearing)
407	    reformat = TRUE;
408	if (max_right != pinfo->maxbounds.rightSideBearing)
409	    reformat = TRUE;
410	dstbpr = GLWIDTHBYTESPADDED(max_right - min_left, scanlinepad);
411	break;
412    case BitmapFormatImageRectMin:
413	break;
414    }
415    if (mappad == BitmapFormatImageRectMax)
416	charsize = dstbpr * height;
417    size = 0;
418    gdata = NULL;
419    contiguous = TRUE;
420    l = lengths;
421    inkChars = inkCharsFree;
422    bitChars = bitCharsFree;
423    for (i = 0; i < nchars; i++)
424    {
425    	inkc = bitc = *bitChars++;
426	/* when ink metrics != bitmap metrics, use ink metrics */
427	if (inkChars)
428	    inkc = *inkChars++;
429    	l->position = size;
430	/*
431         * Do not repad characters with no bits except for those
432         * with non-zero width.
433         */
434        if (bitc && (bitc->bits || bitc->metrics.characterWidth)) {
435	    if (!gdata)
436		gdata = (pointer) bitc->bits;
437	    if ((char *) gdata + size != bitc->bits)
438		contiguous = FALSE;
439	    if (mappad == BitmapFormatImageRectMin)
440		dstbpr = GLYPH_SIZE(inkc, scanlinepad);
441	    if (dstbpr != GLYPH_SIZE(bitc, src_glyph_pad)) reformat = TRUE;
442	    if (mappad != BitmapFormatImageRectMax)
443	    {
444		height = inkc->metrics.ascent + inkc->metrics.descent;
445		charsize = height * dstbpr;
446	    }
447	    l->length = charsize;
448	    size += charsize;
449	}
450	else
451	    l->length = 0;
452	l++;
453    }
454    if (contiguous && !reformat)
455    {
456	*num_glyphs = nchars;
457	*freeData = FALSE;
458	*data = gdata;
459	*tsize = size;
460	*offsets = lengths;
461	FSfree (bitCharsFree);
462	FSfree (inkCharsFree);
463	return Successful;
464    }
465    if (size)
466    {
467	gdata = (pointer) FScalloc(1, size);
468	if (!gdata) {
469	    FSfree (bitCharsFree);
470	    FSfree (inkCharsFree);
471	    FSfree (lengths);
472	    return AllocError;
473	}
474    }
475    else
476	gdata = NULL;
477
478    *freeData = TRUE;
479    l = lengths;
480    gd = gdata;
481
482    /* finally do the work */
483    bitChars = bitCharsFree;
484    inkChars = inkCharsFree;
485    for (i = 0; i < nchars; i++, l++)
486    {
487	inkc = bitc = *bitChars++;
488	if (inkChars)
489	    inkc = *inkChars++;
490
491	/* ignore missing chars */
492	if (l->length == 0)
493	    continue;
494
495	bitm = &bitc->metrics;
496	inkm = &inkc->metrics;
497
498	/* start address for the destination of bits for this char */
499
500	dstp = gd;
501
502	if (mappad == BitmapFormatImageRectMax)
503	    height = max_ascent + max_descent;
504	else
505	    height = inkm->ascent + inkm->descent;
506
507	/* adjust destination and calculate shift offsets */
508	switch (mappad) {
509	case BitmapFormatImageRectMax:
510	    /* leave the first padded rows blank */
511	    if (max_ascent > inkm->ascent)
512	    {
513		height -= (max_ascent - inkm->ascent);
514		dstp += dstbpr * (max_ascent - inkm->ascent);
515	    }
516	    if (max_descent > inkm->descent)
517	    {
518		height -= (max_descent - inkm->descent);
519	    }
520	    /* fall thru */
521	case BitmapFormatImageRectMaxWidth:
522	    dst_off = inkm->leftSideBearing - min_left;
523	    if (dst_off < 0) dst_off = 0;
524	    break;
525	case BitmapFormatImageRectMin:
526	    dst_off = 0;
527	    dstbpr = GLYPH_SIZE(inkc, scanlinepad);
528	    break;
529	}
530
531	srcbpr = GLYPH_SIZE (bitc, src_glyph_pad);
532	srcp = (unsigned char *) bitc->bits;
533
534	/* adjust source */
535	src_off = 0;
536	if (inkm != bitm)
537	{
538	    srcp += (bitm->ascent - inkm->ascent) * srcbpr;
539	    src_off = inkm->leftSideBearing - bitm->leftSideBearing;
540	}
541
542	dst_left_bytes = dst_off >> 3;
543	dst_off &= 7;
544	src_left_bytes = src_off >> 3;
545	src_off &= 7;
546
547	/* minimum of source/dest bytes per row */
548	width = srcbpr - src_left_bytes;
549	if (width > dstbpr - dst_left_bytes)
550	    width = dstbpr - dst_left_bytes;
551	/* extra bytes in source and dest for padding */
552	src_extra = srcbpr - width - src_left_bytes;
553	dst_extra = dstbpr - width - dst_left_bytes;
554
555#define MSBBitLeft(b,c)	((b) << (c))
556#define MSBBitRight(b,c)	((b) >> (c))
557#define LSBBitLeft(b,c)	((b) >> (c))
558#define LSBBitRight(b,c)	((b) << (c))
559
560	if (dst_off == src_off)
561	{
562	    if (srcbpr == dstbpr && src_left_bytes == dst_left_bytes)
563	    {
564		r = height * srcbpr;
565		memmove( dstp, srcp, r);
566		dstp += r;
567	    }
568	    else
569	    {
570		for (r =  height; r; r--)
571		{
572		    dstp += dst_left_bytes;
573		    srcp += src_left_bytes;
574		    for (w = width; w; w--)
575			*dstp++ = *srcp++;
576		    dstp += dst_extra;
577		    srcp += src_extra;
578		}
579	    }
580	}
581	else
582	{
583	    if (dst_off > src_off)
584	    {
585	    	rshift = dst_off - src_off;
586	    	lshift = 8 - rshift;
587	    }
588	    else
589	    {
590	    	lshift = src_off - dst_off;
591	    	rshift = 8 - lshift;
592		/* run the loop one fewer time if necessary */
593		if (src_extra <= dst_extra)
594		{
595		    dst_extra++;
596		    width--;
597		}
598		else
599		    src_extra--;
600	    }
601
602	    for (r = inkm->ascent + inkm->descent; r; r--)
603	    {
604		dstp += dst_left_bytes;
605		srcp += src_left_bytes;
606		bits2 = 0;
607		/* fetch first part of source when necessary */
608		if (dst_off < src_off)
609		    bits2 = *srcp++;
610		/*
611 		 * XXX I bet this does not work when
612		 * src_bit_order != src_byte_order && scanlineunit > 1
613		 */
614		for (w = width; w; w--)
615		{
616		    bits1 = *srcp++;
617		    if (src_bit_order == MSBFirst)
618		    {
619			*dstp++ = MSBBitRight(bits1, rshift) |
620				 MSBBitLeft (bits2, lshift);
621		    }
622		    else
623		    {
624			*dstp++ = LSBBitRight(bits1, rshift) |
625				 LSBBitLeft (bits2, lshift);
626		    }
627		    bits2 = bits1;
628		}
629		/* get the last few bits if we have a place to store them */
630		if (dst_extra > 0)
631		{
632		    if (src_bit_order == MSBFirst)
633			*dstp = MSBBitLeft (bits2, lshift);
634		    else
635			*dstp = LSBBitLeft (bits2, lshift);
636		}
637		dstp += dst_extra;
638		srcp += src_extra;
639	    }
640	}
641	/* skip the amount we just filled in */
642	gd += l->length;
643    }
644
645
646    /* now do the bit, byte, word swapping */
647    if (bitorder != src_bit_order)
648	BitOrderInvert(gdata, size);
649    if (byteorder != src_byte_order)
650    {
651	if (scanlineunit == 2)
652	    TwoByteSwap(gdata, size);
653	else if (scanlineunit == 4)
654	    FourByteSwap(gdata, size);
655    }
656    FSfree (bitCharsFree);
657    FSfree (inkCharsFree);
658    *num_glyphs = nchars;
659    *data = gdata;
660    *tsize = size;
661    *offsets = lengths;
662
663    return Successful;
664}
665
666/* ARGSUSED */
667int
668GetBitmaps(
669    ClientPtr   client,
670    FontPtr     pfont,
671    fsBitmapFormat format,
672    Mask        flags,
673    unsigned long num_ranges,
674    fsRange    *range,
675    int        *size,
676    unsigned long *num_glyphs,
677    fsOffset32  **offsets,
678    pointer    *data,
679    int		*freeData)
680{
681    int err;
682
683    assert(pfont);
684
685    *size = 0;
686    *data = (pointer) 0;
687
688    err = LoadGlyphRanges(client, pfont, TRUE, num_ranges * 2, 0,
689			  (fsChar2b *)range);
690
691    if (err != Successful)
692	return err;
693
694    return packGlyphs (client, pfont, format, flags,
695			      num_ranges, range, size, num_glyphs,
696			      offsets, data, freeData);
697}
698