home *** CD-ROM | disk | FTP | other *** search
/ Languages Around the World / LanguageWorld.iso / language / japanese / win_prog / win_jwp / font.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-31  |  14.5 KB  |  556 lines

  1. /* Copyright (C) Stephen Chung, 1991-1993.  All rights reserved. */
  2.  
  3. #include "jwp.h"
  4.  
  5. #include <math.h>
  6.  
  7.  
  8. typedef struct fontcache {
  9.     KANJIFONT *font;
  10.     int width, height;
  11.     int size, bmsize;
  12.     int far *indexes;
  13.     BYTE far *bitmaps;
  14.     long int requests, hits, usage;
  15.     struct fontcache far *next, far *prev;
  16. } FONTCACHE;
  17.  
  18. static FONTCACHE far *FontCaches;          /* Base font always the first */
  19. static BYTE far *BaseKana = NULL;
  20. static int BaseKanaSize;
  21. static long int BaseRequests = 0L, BaseHits = 0L;
  22.  
  23. static BOOL CacheEnabled = TRUE;
  24. static BYTE far *CharBitmap = NULL;
  25.  
  26. #define DEFAULTLEADING   (1.0 / 8.0)
  27. #define DEFAULTSPACING   (1.0 / 8.0)
  28. #define KANASTART        0x2421
  29. #define KANALENGTH       83
  30. #define SYSCACHELEN      300
  31. #define OTHERCACHELEN     100
  32.  
  33.  
  34.  
  35. static int AdjustBitmapWidth(int bytes)
  36. {
  37.     int bmwidth;
  38.  
  39.     if (bytes % sizeof(int)) {
  40.         bmwidth = (bytes / sizeof(int)) + 1;
  41.         bmwidth *= sizeof(int);
  42.     } else {
  43.         bmwidth = bytes;
  44.     }
  45.  
  46.     return (bmwidth);
  47. }
  48.  
  49.  
  50.  
  51. int AllignKanjiBitmap (BYTE far *buffer, BYTE far *source, int bytes, int lines)
  52. {
  53.     int i, j, m, n;
  54.     int bmwidth;
  55.  
  56.     bytes /= lines;
  57.  
  58.     bmwidth = AdjustBitmapWidth(bytes);
  59.  
  60.     if (bmwidth == bytes) {
  61.         _fmemcpy(buffer, source, bytes * lines);
  62.     } else {
  63.         for (j = 0; j < lines; j++) {
  64.             m = j * bytes;
  65.             n = j * bmwidth;
  66.  
  67.             for (i = 0; i < bmwidth; i++)
  68.                 buffer[n + i] = (i >= bytes) ? 0 : source[m + i];
  69.         }
  70.     }
  71.  
  72.     return (bmwidth * lines);
  73. }
  74.  
  75.  
  76.  
  77. int OpenFont(char *fname, KANJIFONT *f)
  78. {
  79.     int fd;
  80.     FONTHEADER fh;
  81.  
  82.     for (;;) {
  83.         fd = OpenFile(fname, &(f->of), OF_READ);
  84.         if (fd >= 0) break;
  85.         if (!RetryMessage ("Cannot open font file '%s'!", fname)) return (-1);
  86.     }
  87.  
  88.     lseek(fd, 0L, 0);
  89.     read(fd, &fh, sizeof(FONTHEADER));
  90.  
  91.     f->facename = (KANJI *) MemAlloc(NAMELEN);
  92.     kanjicpy(f->facename, fh.facename);
  93.     f->filename = (char *) MemAlloc(strlen(fname) + 5);
  94.     strcpy(f->filename, fname);
  95.  
  96.     f->width = fh.width;
  97.     f->height = fh.height;
  98.     f->bmsize = fh.charsize;
  99.     f->offset = fh.offset;
  100.     f->verticals = fh.verticals;
  101.     f->holes = fh.holes;
  102.  
  103.     f->leading = (fh.leading <= 0) ? (double) f->width * DEFAULTLEADING : fh.leading;
  104.     f->spacing = (fh.spacing <= 0) ? (double) f->height * DEFAULTSPACING : fh.spacing;
  105.  
  106.     return (fd);
  107. }
  108.  
  109.  
  110. void EnableFontCache (BOOL On)
  111. {
  112.     CacheEnabled = On;
  113.  
  114.     if (On) {
  115.         if (CharBitmap != NULL) FreeBlock(CharBitmap);
  116.         CharBitmap = NULL;
  117.     }
  118. }
  119.  
  120.  
  121.  
  122. static FONTCACHE far *CreateCache (KANJIFONT *font, int size, int bmsize)
  123. {
  124.     int i;
  125.     long int block;
  126.     FONTCACHE far *f;
  127.  
  128.     if (FontCaches == NULL) {
  129.         FontCaches = f = StructAlloc(FONTCACHE);
  130.         f->prev = f->next = NULL;
  131.     } else {
  132.         for (f = FontCaches; f->next != NULL; f = f->next);
  133.         f->next = StructAlloc(FONTCACHE);
  134.         f->next->prev = f;
  135.         f = f->next;
  136.         f->next = NULL;
  137.     }
  138.     if (f == NULL) return (NULL);
  139.  
  140.     block = (long int) size * sizeof(int);
  141.     if (block > C64K) { size = C64K / bmsize; block = (long int) size * sizeof(int); }
  142.     f->indexes = (int far *) BlockAlloc(block);
  143.  
  144.     block = (long int) size * (long int) bmsize;
  145.     if (block > C64K) { size = C64K / bmsize; block = (long int) size * (long int) bmsize; }
  146.     f->bitmaps = (BYTE far *) BlockAlloc(block);
  147.  
  148.  
  149.     f->font = font;
  150.     f->width = font->width;
  151.     f->height = font->height;
  152.     f->size = size;
  153.     f->bmsize = bmsize;
  154.     f->requests = f->hits = f->usage = 0L;
  155.  
  156.     for (i = 0; i < size; i++) f->indexes[i] = -1;
  157.     return (f);
  158. }
  159.  
  160.  
  161.  
  162. HFONT SelectAsciiFont (HDC hdc, char *facename, double ps, TEXTMETRIC *tmout)
  163. {
  164.     int size;
  165.     HFONT hfont, oldfont;
  166.     TEXTMETRIC tm;
  167.     char buffer[MAXLINELEN];
  168.  
  169.     size = (int) floor(ps * global.resolution.y / 72.0 + 0.5);
  170.     hfont = CreateFont(-size, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
  171.                        CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FF_DONTCARE, facename);
  172.  
  173.     oldfont = SelectObject(hdc, hfont);
  174.     GetTextMetrics(hdc, &tm);
  175.  
  176.     GetTextFace(hdc, MAXLINELEN, buffer);
  177.  
  178.  
  179.     if (stricmp(buffer, facename)) {
  180.         ErrorMessage(global.hwnd, "The font '%s' is not available in this size.  The font "
  181.                                   "'%s' will be used instead.", facename, buffer);
  182.     }
  183.  
  184.     SelectObject(hdc, oldfont);
  185.     if (tmout != NULL) *tmout = tm;
  186.  
  187.     return (hfont);
  188. }
  189.  
  190.  
  191.  
  192. HFONT FindMatchingScreenFont (HFONT hfont, double scale, TEXTMETRIC *tmout)
  193. {
  194.     int size;
  195.     HDC hdc;
  196.     TEXTMETRIC tm;
  197.     HFONT screenfont;
  198.     char buffer[MAXLINELEN];
  199.  
  200.     hdc = GetPrinterDC(TRUE, NULL);
  201.     if (hdc == NULL) hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  202.  
  203.     SelectObject(hdc, hfont);
  204.     GetTextMetrics(hdc, &tm);
  205.     GetTextFace(hdc, MAXLINELEN, buffer);
  206.     DeleteDC(hdc);
  207.     hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  208.  
  209.     size = (int) floor((double) (tm.tmHeight - tm.tmInternalLeading) * scale + 0.5);
  210.  
  211.     screenfont = CreateFont(-size, 0, 0, 0, tm.tmWeight,
  212.                             tm.tmItalic, tm.tmUnderlined, tm.tmStruckOut,
  213.                             tm.tmCharSet, OUT_DEFAULT_PRECIS,
  214.                             CLIP_DEFAULT_PRECIS, DRAFT_QUALITY,
  215.                             tm.tmPitchAndFamily, buffer);
  216.  
  217.     SelectObject(hdc, screenfont);
  218.     if (tmout != NULL) GetTextMetrics(hdc, tmout);
  219.     GetTextFace(hdc, MAXLINELEN, buffer);
  220.  
  221.     DeleteDC(hdc);
  222.  
  223.     return (screenfont);
  224. }
  225.  
  226.  
  227.  
  228. int InitFonts(void)
  229. {
  230.     int i, fd;
  231.     long int size, kanastart;
  232.     HFONT hfont;
  233.     BYTE charbuf[BUFSIZE];
  234.  
  235.  
  236.     /* The system font should have been opened already */
  237.  
  238.     fd = OpenFile(NULL, &(SYSFONT->of), OF_READ | OF_REOPEN);
  239.     if (fd < 0) {
  240.         ErrorMessage(global.hwnd, "Funny!  System font not opened yet!\n\n"
  241.                                      "Program will die now.");
  242.         exit(-1);
  243.     }
  244.  
  245.     /* Get the adjusted size of a bitmap */
  246.  
  247.     BaseKanaSize = AdjustBitmapWidth(SYSFONT->bmsize / SYSFONT->height) * SYSFONT->height;
  248.  
  249.     /* Create the system kana cache */
  250.  
  251.     size = (long int) KANALENGTH * BaseKanaSize;
  252.  
  253.     if (size < C64K) {
  254.         /* Allocate the kanagana font cache */
  255.         /* #210 for 169 */
  256.  
  257.         BaseKana = (BYTE far *) BlockAlloc(size);
  258.  
  259.         kanastart = Jis2Index(KANASTART, SYSFONT->holes);
  260.  
  261.         for (i = 0; i < KANALENGTH; i++, kanastart++) {
  262.             lseek(fd, kanastart * (long int) SYSFONT->bmsize + SYSFONT->offset, 0);
  263.             read(fd, charbuf, SYSFONT->bmsize);
  264.             AllignKanjiBitmap (&(BaseKana[i * BaseKanaSize]), charbuf, SYSFONT->bmsize, SYSFONT->height);
  265.         }
  266.     }
  267.  
  268.     close(fd);
  269.  
  270.     BaseRequests = BaseHits = 0L;
  271.  
  272.     /* Allocate the system font cache */
  273.  
  274.     FontCaches = NULL;
  275.  
  276.     size = (long int) SYSCACHELEN * BaseKanaSize;
  277.  
  278.     if (size > C64K) size = C64K / BaseKanaSize;
  279.     else size = SYSCACHELEN;
  280.  
  281.     FontCaches = CreateCache (SYSFONT, size, BaseKanaSize);
  282.  
  283.     hfont = CreateFont((int) -floor(DefAsciiFont.size * global.resolution.y / 72.0 + 0.5),
  284.                        0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
  285.                        CLIP_DEFAULT_PRECIS, PROOF_QUALITY, FF_DONTCARE, DefAsciiFont.facename);
  286.  
  287.     DefAsciiFont.hfont =
  288.         FindMatchingScreenFont(hfont, global.dispscale / global.printscale,
  289.                                &(DefAsciiFont.textmetric));
  290.     DeleteObject(hfont);
  291.  
  292.     FontCharWidth(0, -2);       /* Load the width tables */
  293.     return (1);
  294. }
  295.  
  296.  
  297. static int FontHash (int index, int bins)
  298. {
  299.     return (index % bins);
  300. }
  301.  
  302.  
  303.  
  304. BOOL IsSmallKana(KANJI jiscode)
  305. {
  306.     BYTE hi, lo;
  307.  
  308.     hi = HIBYTE(jiscode) & 0x7f;
  309.     lo = LOBYTE(jiscode) & 0x7f;
  310.  
  311.     if (hi == 0x24 || hi == 0x25) {         /* Hiragana & Katakana */
  312.  
  313.         switch (lo) {
  314.             case 0x21: /* a */
  315.             case 0x23: /* i */
  316.             case 0x25: /* u */
  317.             case 0x27: /* e */
  318.             case 0x29: /* o */
  319.             case 0x63: /* ya */
  320.             case 0x65: /* yu */
  321.             case 0x67: /* yo */
  322.             case 0x43: /* tu */
  323.                 return (TRUE);
  324.  
  325.             default:
  326.                 return (FALSE);
  327.         }
  328.  
  329.     } else if (hi == 0x21) {
  330.  
  331.         switch (lo) {
  332.             case 0x22: /* , */
  333.             case 0x23: /* . */
  334.             case 0x57: /* ' */
  335.             case 0x59: /* '' */
  336.                 return (TRUE);
  337.  
  338.             default:
  339.                 return (FALSE);
  340.         }
  341.  
  342.     }
  343.  
  344.     return (FALSE);
  345. }
  346.  
  347.  
  348. /* The following routine came from KD, the Kanji Driver program  */
  349. /* written by Izumi Ozawa.  It was reformatted and slightly      */
  350. /* modified.  Many thanks to Izumi for his donation.             */
  351.  
  352. int Jis2Index (KANJI jiscode, BOOL holes)
  353. {
  354.     LONG hi, lo;
  355.  
  356.     hi = HIBYTE(jiscode) & 0x007f;
  357.     lo = LOBYTE(jiscode) & 0x007f;
  358.  
  359.  
  360.     if (lo <= 0x20 || lo >= 0x7f || hi <= 0x20 || hi >= 0x74)
  361.         return (-1);
  362.  
  363.     hi = 94 * (hi - 33) + (lo - 33);
  364.  
  365.     if (holes) return (hi);
  366.  
  367.  
  368.     /* Skip the holes */
  369.  
  370.     if (hi <= 107)
  371.         return (hi);        /* 0..93               $2121-$217e, 0  -93   */
  372.                             /* 94..107             $2221-$222e, 94 -107  */
  373.     else if (hi >= 203 && hi <= 212)
  374.         return (hi - 56);   /* 203..212   0 .. 9,  $2330-$2339, 147-156  */
  375.     else if (hi >= 220 && hi <= 245)
  376.         return (hi - 63);   /* 220..245   A .. Z,  $2341-$235a, 157-182  */
  377.     else if (hi >= 252 && hi <= 277)
  378.         return (hi - 69);   /* 252..277   a .. z,  $2361-$237a, 183-208  */
  379.     else if (hi >= 282 && hi <= 364)
  380.         return (hi - 73);   /* 282..364  hiragana, $2421-$2473, 209-291  */
  381.     else if (hi >= 376 && hi <= 461)
  382.         return (hi - 84);   /* 376..461  katakana, $2521-$2576, 292-377  */
  383.     else if (hi >= 470 && hi <= 493)
  384.         return (hi - 92);   /* 470..493   GREEK,   $2621-$2638, 378-401  */
  385.     else if (hi >= 502 && hi <= 525)
  386.         return (hi - 100);  /* 502..525   greek,   $2641-$2658, 402-425  */
  387.     else if (hi >= 564 && hi <= 596)
  388.         return (hi - 138);  /* 564..596   RUSSIAN, $2721-$2741, 426-458  */
  389.     else if (hi >= 612 && hi <= 644)
  390.         return (hi - 153);  /* 612..644   russian, $2751-$2771, 459-491  */
  391.                             /*  n/a       linedraw,  n/a      , 492-523  */
  392.     else if (hi >= 1410 && hi <= 4374)
  393.         return (hi - 886);  /* 1410..4374 kanji-1, $3021-$4f53, 524-3488 */
  394.     else if (hi >= 4418 && hi <= 7805)
  395.         return (hi - 928);  /* 4418..7805 kanji-2, $5021-$737e, 3490-6877 */
  396.  
  397.     /* No such kanji */
  398.  
  399.     return (-1);
  400. }
  401.  
  402.  
  403.  
  404. int GetKanjiBitmap (KANJIFONT *font, int index, BYTE far * *bitsbuffer)
  405. {
  406.     int fd, i, j, k;
  407.     long int size, kanastart;
  408.     FONTCACHE far *f;
  409.     BYTE charbuf[BUFSIZE];
  410.  
  411.     if (BaseKana != NULL && font == SYSFONT) {
  412.         /* Kana's? */
  413.         kanastart = Jis2Index(KANASTART, font->holes);
  414.         if (index >= kanastart && index < kanastart + KANALENGTH) {
  415.             BaseRequests++;
  416.             BaseHits++;
  417.             *bitsbuffer = &(BaseKana[(index - kanastart) * BaseKanaSize]);
  418.             return (BaseKanaSize);
  419.         }
  420.     }
  421.  
  422.     /* Is the font cached? */
  423.  
  424.     for (f = FontCaches; f != NULL; f = f->next) {
  425.         if (f->font == font) break;
  426.     }
  427.     if (f != NULL) {
  428.         i = FontHash(index, f->size);
  429.         for (j = i; ;) {
  430.             k = f->indexes[j];          /* The cached value */
  431.  
  432.             if (k < 0) break;
  433.             //if (FontHash(k, f->size) != i) break;
  434.  
  435.             if (k == index) {           /* Found it! */
  436.                 f->requests++;
  437.                 f->hits++;
  438.                 *bitsbuffer = &(f->bitmaps[f->bmsize * j]);
  439.                 return (f->bmsize);
  440.             }
  441.             if (++j >= f->size) j = 0;  /* Wrap around */
  442.             if (j == i) break;          /* Complete cycle */
  443.         }
  444.     }
  445.  
  446.     if (CacheEnabled) {
  447.         /* Put it in the cache! */
  448.  
  449.         if (f == NULL && CacheEnabled) {
  450.             i = AdjustBitmapWidth(font->bmsize / font->height) * font->height;
  451.             size = (long int) OTHERCACHELEN * i;
  452.  
  453.             if (size > C64K) size = C64K / i;
  454.             else size = OTHERCACHELEN;
  455.  
  456.             f = CreateCache (font, size, i);
  457.         }
  458.  
  459.         if (f == NULL) {
  460.             *bitsbuffer = NULL;
  461.             return (0);
  462.         }
  463.  
  464.         i = FontHash (index, f->size);
  465.  
  466.         for (j = i; ;) {
  467.             if (f->indexes[j] < 0) break;
  468.             if (++j >= f->size) j = 0;      /* Wrap around */
  469.             if (j == i) {                   /* Complete cycle */
  470.                 j = rand() % f->size;       /* Bump out a random one */
  471.                 break;
  472.             }
  473.         }
  474.  
  475.         if (f->indexes[j] < 0) f->usage++;
  476.  
  477.         f->indexes[j] = index;
  478.  
  479.         f->requests++;
  480.     }
  481.  
  482.     fd = OpenFile(NULL, &(font->of), OF_READ | OF_REOPEN);
  483.     lseek(fd, (long int) index * (long int) font->bmsize + font->offset, 0);
  484.     read(fd, charbuf, font->bmsize);
  485.     close(fd);
  486.  
  487.     if (CacheEnabled) {
  488.         AllignKanjiBitmap (&(f->bitmaps[f->bmsize * j]), charbuf, font->bmsize, font->height);
  489.  
  490.         *bitsbuffer = &(f->bitmaps[f->bmsize * j]);
  491.  
  492.         return (f->bmsize);
  493.     } else {
  494.         if (CharBitmap == NULL) CharBitmap = (BYTE far *) BlockAlloc(BUFSIZE);
  495.  
  496.         i = AllignKanjiBitmap (CharBitmap, charbuf, font->bmsize, font->height);
  497.  
  498.         *bitsbuffer = CharBitmap;
  499.  
  500.         return (i);
  501.     }
  502. }
  503.  
  504.  
  505. void DisplayKanjiBitmap(HDC hdc, int x, int y, int width, int height, int size,
  506.                         DWORD style, BYTE far *bits)
  507. {
  508.     HDC hdcmem;
  509.     static HANDLE hbitmap = NULL;
  510.     static lastwidth = 0, lastheight = 0;
  511.  
  512.     /* size = -1 means deallocate */
  513.  
  514.     if (size < 0) {
  515.         if (hbitmap != NULL) DeleteObject(hbitmap);
  516.         return;
  517.     }
  518.  
  519.  
  520.     /* Do we need to allocate a new bitmap? */
  521.  
  522.     if (width != lastwidth || height != lastheight) {
  523.         if (hbitmap != NULL) DeleteObject(hbitmap);
  524.         hbitmap = NULL;
  525.         lastwidth = width;
  526.         lastheight = height;
  527.     }
  528.     if (hbitmap == NULL) {
  529.         hbitmap = CreateBitmap(width, height, 1, 1, bits);
  530.     } else {
  531.         SetBitmapBits(hbitmap, (DWORD) size, bits);
  532.     }
  533.  
  534.     hdcmem = CreateCompatibleDC(hdc);
  535.     SelectObject(hdcmem, hbitmap);
  536.     SetMapMode(hdcmem, GetMapMode(hdc));
  537.     BitBlt(hdc, x, y - height, width, height, hdcmem, 0, 0, style);
  538.     DeleteDC(hdcmem);
  539. }
  540.  
  541.  
  542. void FontCacheStatistics (int *num, long int *usage, long int *requests, long int *hits)
  543. {
  544.     FONTCACHE far *f;
  545.  
  546.     *requests = 0L;
  547.     *hits = 0L;
  548.     *usage = 0L;
  549.  
  550.     for (*num = 0, f = FontCaches; f != NULL; f = f->next, (*num)++) {
  551.         *requests += f->requests;
  552.         *hits += f->hits;
  553.         *usage += f->usage;
  554.     }
  555. }
  556.