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