(mail-hist-previous-input, mail-hist-next-input): do the obvious code
[emacs.git] / src / w32bdf.c
blob932c874356ffafac956616628c717c74b549135e
1 /* Implementation of BDF font handling on the Microsoft W32 API.
2 Copyright (C) 1999 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Based heavily on code by H. Miyashita for Meadow (a descendant of
22 MULE for W32). */
24 #include <windows.h>
25 #include "config.h"
26 #include "lisp.h"
27 #include "charset.h"
28 #include "frame.h"
29 #include "dispextern.h"
30 #include "fontset.h"
31 #include "blockinput.h"
32 #include "w32gui.h"
33 #include "w32term.h"
34 #include "w32bdf.h"
36 #define min(a, b) ((a) < (b) ? (a) : (b))
37 #define max(a, b) ((a) > (b) ? (a) : (b))
39 /* Portion of GDI Objects which the font cache is allowed to use. This
40 can be quite high, since the font cache is the only part of Emacs
41 that uses a large number of GDI objects, but there should still be
42 some GDI objects reserved for other uses. */
43 #define CACHE_GDI_ALLOWANCE 9 / 10
45 void w32_free_bdf_font(bdffont *fontp);
46 bdffont *w32_init_bdf_font(char *filename);
48 static int
49 search_file_line(char *key, char *start, int len, char **val, char **next)
51 int linelen;
52 unsigned char *p, *q;
54 p = memchr(start, '\n', len);
55 if (!p) return -1;
56 for (;start < p;start++)
58 if ((*start != ' ') || (*start != '\t')) break;
60 linelen = p - start + 1;
61 *next = p + 1;
62 if (strncmp(start, key, min(strlen(key), linelen)) == 0)
64 *val = start + strlen(key);
65 return 1;
68 return 0;
71 static int
72 proceed_file_line(char *key, char *start, int *len, char **val, char **next)
74 int flag = 0;
76 do {
77 flag = search_file_line(key, start, *len, val, next);
78 *len -= (int)(*next - start);
79 start = *next;
80 }while(flag == 0);
82 if (flag == -1) return 0;
83 return 1;
86 char*
87 get_quoted_string(char *start, char *end)
89 char *p, *q, *result;
91 p = memchr(start, '\"', end - start);
92 q = 0;
94 if (!p) return NULL;
95 p++;
96 q = memchr(p, '\"', end - q);
97 if (!q) return NULL;
99 result = (char*) xmalloc(q - p + 1);
101 memcpy(result, p, q - p);
102 result[q - p] = '\0';
104 return result;
107 static int
108 set_bdf_font_info(bdffont *fontp)
110 unsigned char *start, *p, *q;
111 int len, flag;
112 int bbw, bbh, bbx, bby;
113 int val1;
115 len = fontp->size;
116 start = fontp->font;
118 fontp->yoffset = 0;
119 fontp->relative_compose = 0;
120 fontp->default_ascent = 0;
121 fontp->registry = NULL;
122 fontp->encoding = NULL;
123 fontp->slant = NULL;
124 /* fontp->width = NULL; */
126 flag = proceed_file_line("FONTBOUNDINGBOX", start, &len, &p, &q);
127 if (!flag) return 0;
128 bbw = strtol(p, &start, 10);
129 p = start;
130 bbh = strtol(p, &start, 10);
131 p = start;
132 bbx = strtol(p, &start, 10);
133 p = start;
134 bby = strtol(p, &start, 10);
136 fontp->llx = bbx;
137 fontp->lly = bby;
138 fontp->urx = bbw + bbx;
139 fontp->ury = bbh + bby;
140 fontp->width = bbw;
141 fontp->height = bbh;
142 start = q;
143 flag = proceed_file_line("STARTPROPERTIES", start, &len, &p, &q);
144 if (!flag) return 1;
146 flag = 0;
148 do {
149 start = q;
150 if (search_file_line("PIXEL_SIZE", start, len, &p, &q) == 1)
152 val1 = atoi(p);
153 fontp->pixsz = val1;
155 else if (search_file_line("FONT_ASCENT", start, len, &p, &q) == 1)
157 val1 = atoi(p);
158 fontp->ury = val1;
160 else if (search_file_line("FONT_DESCENT", start, len, &p, &q) == 1)
162 val1 = atoi(p);
163 fontp->lly = -val1;
165 else if (search_file_line("_MULE_BASELINE_OFFSET", start, len, &p, &q) == 1)
167 val1 = atoi(p);
168 fontp->yoffset = val1;
170 else if (search_file_line("_MULE_RELATIVE_COMPOSE", start, len, &p, &q) == 1)
172 val1 = atoi(p);
173 fontp->relative_compose = val1;
175 else if (search_file_line("_MULE_DEFAULT_ASCENT", start, len, &p, &q) == 1)
177 val1 = atoi(p);
178 fontp->default_ascent = val1;
180 else if (search_file_line("CHARSET_REGISTRY", start, len, &p, &q) == 1)
182 fontp->registry = get_quoted_string(p, q);
184 else if (search_file_line("CHARSET_ENCODING", start, len, &p, &q) == 1)
186 fontp->encoding = get_quoted_string(p, q);
188 else if (search_file_line("SLANT", start, len, &p, &q) == 1)
190 fontp->slant = get_quoted_string(p, q);
193 else if (search_file_line("SETWIDTH_NAME", start, len, &p, &q) == 1)
195 fontp->width = get_quoted_string(p, q);
198 else
200 flag = search_file_line("ENDPROPERTIES", start, len, &p, &q);
202 if (flag == -1) return 0;
203 len -= (q - start);
204 }while(flag == 0);
205 start = q;
206 flag = proceed_file_line("CHARS", start, &len, &p, &q);
207 if (!flag) return 0;
208 fontp->seeked = q;
210 return 1;
213 bdffont*
214 w32_init_bdf_font(char *filename)
216 HANDLE hfile, hfilemap;
217 bdffont *bdffontp;
218 unsigned char *font;
219 BY_HANDLE_FILE_INFORMATION fileinfo;
220 int i;
222 hfile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
223 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
224 if (hfile == INVALID_HANDLE_VALUE) return NULL;
225 if (!GetFileInformationByHandle(hfile, &fileinfo) ||
226 (fileinfo.nFileSizeHigh != 0) ||
227 (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX))
229 CloseHandle(hfile);
230 error("Fail to open BDF file.");
232 hfilemap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL);
233 if (hfilemap == INVALID_HANDLE_VALUE)
235 CloseHandle(hfile);
236 error("Can't map font.");
239 font = MapViewOfFile(hfilemap, FILE_MAP_READ, 0, 0, 0);
241 if (!font)
243 CloseHandle(hfile);
244 CloseHandle(hfilemap);
245 error("Can't view font.");
248 bdffontp = (bdffont *) xmalloc(sizeof(bdffont));
250 for(i = 0;i < BDF_FIRST_OFFSET_TABLE;i++)
251 bdffontp->chtbl[i] = NULL;
252 bdffontp->size = fileinfo.nFileSizeLow;
253 bdffontp->font = font;
254 bdffontp->hfile = hfile;
255 bdffontp->hfilemap = hfilemap;
256 bdffontp->filename = (char*) xmalloc(strlen(filename) + 1);
257 strcpy(bdffontp->filename, filename);
259 if (!set_bdf_font_info(bdffontp))
261 w32_free_bdf_font(bdffontp);
262 error("Invalid BDF font!");
264 return bdffontp;
267 void
268 w32_free_bdf_font(bdffont *fontp)
270 int i, j;
271 font_char *pch;
272 cache_bitmap *pcb;
274 UnmapViewOfFile(fontp->hfilemap);
275 CloseHandle(fontp->hfilemap);
276 CloseHandle(fontp->hfile);
278 if (fontp->registry) xfree(fontp->registry);
279 if (fontp->encoding) xfree(fontp->encoding);
280 if (fontp->slant) xfree(fontp->slant);
281 /* if (fontp->width) xfree(fontp->width); */
283 xfree(fontp->filename);
284 for(i = 0;i < BDF_FIRST_OFFSET_TABLE;i++)
286 pch = fontp->chtbl[i];
287 if (pch)
289 for (j = 0;j < BDF_SECOND_OFFSET_TABLE;j++)
291 pcb = pch[j].pcbmp;
292 if (pcb) pcb->psrc = NULL;
294 xfree(pch);
297 xfree(fontp);
300 static font_char*
301 get_cached_font_char(bdffont *fontp, int index)
303 font_char *pch, *result;
304 int i;
306 if (index > 0xffff)
307 return NULL;
309 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)];
310 if (!pch)
311 return NULL;
312 result = &pch[BDF_SECOND_OFFSET(index)];
314 if (!result->offset) return NULL;
316 return result;
319 static font_char*
320 cache_char_offset(bdffont *fontp, int index, unsigned char *offset)
322 font_char *pch, *result;
323 int i;
325 if (index > 0xffff)
326 return NULL;
328 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)];
329 if (!pch)
331 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)] =
332 (font_char*) xmalloc(sizeof(font_char) *
333 BDF_SECOND_OFFSET_TABLE);
334 memset(pch, 0, sizeof(font_char) * BDF_SECOND_OFFSET_TABLE);
337 result = &pch[BDF_SECOND_OFFSET(index)];
338 result->offset = offset;
340 return result;
343 static font_char*
344 seek_char(bdffont *fontp, int index)
346 font_char *result;
347 int len, flag, font_index;
348 unsigned char *start, *p, *q;
350 if (!fontp->seeked) return NULL;
352 start = fontp->seeked;
353 len = fontp->size - (start - fontp->font);
355 do {
356 flag = proceed_file_line("ENCODING", start, &len, &p, &q);
357 if (!flag)
359 fontp->seeked = NULL;
360 return NULL;
362 font_index = atoi(p);
363 result = cache_char_offset(fontp, font_index, q);
364 if (!result) return NULL;
366 start = result->offset;
367 } while (font_index != index);
368 fontp->seeked = start;
370 return result;
373 #define GET_HEX_VAL(x) ((isdigit(x)) ? ((x) - '0') : \
374 (((x) >= 'A') && ((x) <= 'Z')) ? ((x) - 'A' + 10) : \
375 (((x) >= 'a') && ((x) <= 'z')) ? ((x) - 'a' + 10) : \
376 (-1))
379 w32_get_bdf_glyph(bdffont *fontp, int index, int size, glyph_struct *glyph)
381 font_char *pch;
382 unsigned char *start, *p, *q, *bitmapp;
383 unsigned char val1, val2;
384 int i, j, len, flag;
386 pch = get_cached_font_char(fontp, index);
387 if (!pch)
389 pch = seek_char(fontp, index);
390 if (!pch)
391 return 0;
394 start = pch->offset;
396 if ((size == 0) && pch->pcbmp)
398 glyph->metric = pch->pcbmp->metric;
399 return 1;
402 len = fontp->size - (start - fontp->font);
404 flag = proceed_file_line("DWIDTH", start, &len, &p, &q);
405 if (!flag)
406 return 0;
407 glyph->metric.dwidth = atoi(p);
409 start = q;
410 flag = proceed_file_line("BBX", start, &len, &p, &q);
411 if (!flag)
412 return 0;
413 glyph->metric.bbw = strtol(p, &start, 10);
414 p = start;
415 glyph->metric.bbh = strtol(p, &start, 10);
416 p = start;
417 glyph->metric.bbox = strtol(p, &start, 10);
418 p = start;
419 glyph->metric.bboy = strtol(p, &start, 10);
421 if (size == 0) return 1;
423 start = q;
424 flag = proceed_file_line("BITMAP", start, &len, &p, &q);
425 if (!flag)
426 return 0;
428 p = q;
429 bitmapp = glyph->bitmap;
430 for(i = 0;i < glyph->metric.bbh;i++)
432 q = memchr(p, '\n', len);
433 if (!q) return 0;
434 for(j = 0;((q > p) && (j < ((glyph->metric.bbw + 7) / 8 )));j++)
436 val1 = GET_HEX_VAL(*p);
437 if (val1 == -1) return 0;
438 p++;
439 val2 = GET_HEX_VAL(*p);
440 if (val2 == -1) return 0;
441 p++;
442 size--;
443 if (size <= 0) return 0;
444 /* NAND Operation. */
445 *bitmapp++ = (unsigned char)~((val1 << 4) | val2);
447 /* CreateBitmap requires WORD alignment. */
448 if (j % 2)
450 *bitmapp++ = 0xff;
452 p = q + 1;
455 return 1;
458 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
460 static
461 cache_bitmap*
462 get_bitmap_with_cache(bdffont *fontp, int index)
464 int bitmap_size;
465 font_char *pch;
466 cache_bitmap* pcb;
467 HBITMAP hbmp;
468 glyph_struct glyph;
469 static cache_bitmap cached_bitmap_slots[BDF_FONT_CACHE_SIZE];
470 static int cache_in_slot = 0; /* the next slot to use */
471 static int cache_out_slot = 0; /* the last slot allocated */
472 static int cache_occupancy = 0; /* current cache occupancy */
473 static int cache_limit = BDF_FONT_CACHE_SIZE; /* allowed maximum occupancy */
475 pch = get_cached_font_char(fontp, index);
476 if (pch)
478 pcb = pch->pcbmp;
479 if (pcb) return pcb;
482 bitmap_size = ((fontp->urx - fontp->llx) / 8 + 2) * (fontp->ury - fontp->lly)
483 + 256;
484 glyph.bitmap = (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size);
486 if (!w32_get_bdf_glyph(fontp, index, bitmap_size, &glyph))
487 return NULL;
489 pch = get_cached_font_char(fontp, index);
490 if (!pch) return NULL;
492 hbmp = CreateBitmap(glyph.metric.bbw, glyph.metric.bbh, 1, 1, glyph.bitmap);
494 /* if bitmap allocation fails reduce the limit of the occupancy so
495 that we can hope it will not happen again. */
496 if (hbmp == NULL)
497 cache_limit = cache_occupancy * CACHE_GDI_ALLOWANCE;
499 /* if cache occupancy reaches at the limit release some cache slots */
500 if (cache_occupancy >= cache_limit)
502 register int size_to_clear = cache_limit * BDF_FONT_CLEAR_SIZE
503 / BDF_FONT_CACHE_SIZE;
504 for (; size_to_clear; size_to_clear--,
505 cache_out_slot = NEXT_CACHE_SLOT(cache_out_slot))
507 register cache_bitmap *p = &cached_bitmap_slots[cache_out_slot];
508 if (p->psrc)
510 DeleteObject(p->hbmp);
511 p->psrc->pcbmp = NULL;
512 p->psrc = NULL;
513 cache_occupancy--;
518 if (hbmp == NULL)
519 hbmp = CreateBitmap (glyph.metric.bbw, glyph.metric.bbh,
520 1, 1, glyph.bitmap);
522 pcb = &cached_bitmap_slots[cache_in_slot];
524 pcb->psrc = pch;
525 pcb->metric = glyph.metric;
526 pcb->hbmp = hbmp;
528 pch->pcbmp = pcb;
530 cache_in_slot = NEXT_CACHE_SLOT(cache_in_slot);
531 cache_occupancy++;
533 return pcb;
537 w32_BDF_TextOut(bdffont *fontp, HDC hdc, int left,
538 int top, unsigned char *text, int dim, int bytelen,
539 int fixed_pitch_size)
541 int index, btop;
542 unsigned char *textp;
543 HDC hCompatDC = 0;
544 cache_bitmap *pcb;
545 HBITMAP hBMP;
546 HBRUSH hFgBrush, hOrgBrush;
547 HANDLE horgobj = 0;
548 UINT textalign;
549 int flag = 0;
551 hCompatDC = CreateCompatibleDC(hdc);
553 textalign = GetTextAlign(hdc);
555 SaveDC(hdc);
557 hFgBrush = CreateSolidBrush(GetTextColor(hdc));
558 hOrgBrush = SelectObject(hdc, hFgBrush);
559 SetTextColor(hdc, RGB(0, 0, 0));
560 SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
562 textp = text;
563 while(bytelen > 0)
565 if (dim == 1)
567 index = *textp++;
568 bytelen--;
570 else
572 bytelen -= 2;
573 if (bytelen < 0) break;
574 index = MAKELENDSHORT(textp[1], textp[0]);
575 textp += 2;
577 pcb = get_bitmap_with_cache(fontp, index);
578 if (!pcb)
580 if (horgobj)
582 SelectObject(hCompatDC, horgobj);
583 DeleteObject(hBMP);
585 DeleteDC(hCompatDC);
586 return 0;
588 hBMP = pcb->hbmp;
590 if (textalign & TA_BASELINE)
591 btop = top - (pcb->metric.bbh + pcb->metric.bboy);
592 else if (textalign & TA_BOTTOM)
593 btop = top - pcb->metric.bbh;
594 else
595 btop = top;
597 if (horgobj)
598 SelectObject(hCompatDC, hBMP);
599 else
600 horgobj = SelectObject(hCompatDC, hBMP);
601 #if 0
602 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, SRCCOPY);
603 #else
604 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, 0xB8074A);
605 #endif
606 if (fixed_pitch_size)
607 left += fixed_pitch_size;
608 else
609 left += pcb->metric.dwidth;
611 SelectObject(hCompatDC, horgobj);
612 SelectObject(hdc, hOrgBrush);
613 DeleteObject(hFgBrush);
614 DeleteDC(hCompatDC);
615 RestoreDC(hdc, -1);
617 return 1;
620 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
621 int size, char* filename)
623 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
624 struct font_info *fontp;
625 XFontStruct *font;
626 bdffont* bdf_font;
628 bdf_font = w32_init_bdf_font (filename);
630 if (!bdf_font) return NULL;
632 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
634 font->bdf = bdf_font;
635 font->hfont = 0;
637 /* NTEMACS_TODO: Recognize DBCS fonts. */
638 font->double_byte_p = 0;
640 /* Do we need to create the table? */
641 if (dpyinfo->font_table_size == 0)
643 dpyinfo->font_table_size = 16;
644 dpyinfo->font_table
645 = (struct font_info *) xmalloc (dpyinfo->font_table_size
646 * sizeof (struct font_info));
648 /* Do we need to grow the table? */
649 else if (dpyinfo->n_fonts
650 >= dpyinfo->font_table_size)
652 dpyinfo->font_table_size *= 2;
653 dpyinfo->font_table
654 = (struct font_info *) xrealloc (dpyinfo->font_table,
655 (dpyinfo->font_table_size
656 * sizeof (struct font_info)));
659 fontp = dpyinfo->font_table + dpyinfo->n_fonts;
661 /* Now fill in the slots of *FONTP. */
662 BLOCK_INPUT;
663 fontp->font = font;
664 fontp->font_idx = dpyinfo->n_fonts;
665 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
666 bcopy (fontname, fontp->name, strlen (fontname) + 1);
667 fontp->full_name = fontp->name;
668 fontp->size = FONT_WIDTH (font);
669 fontp->height = FONT_HEIGHT (font);
671 /* The slot `encoding' specifies how to map a character
672 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
673 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
674 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
675 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
676 2:0xA020..0xFF7F). For the moment, we don't know which charset
677 uses this font. So, we set informatoin in fontp->encoding[1]
678 which is never used by any charset. If mapping can't be
679 decided, set FONT_ENCODING_NOT_DECIDED. */
680 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
681 fontp->baseline_offset = bdf_font->yoffset;
682 fontp->relative_compose = bdf_font->relative_compose;
683 fontp->default_ascent = bdf_font->default_ascent;
685 UNBLOCK_INPUT;
686 dpyinfo->n_fonts++;
687 return fontp;
690 /* Check a file for an XFLD string describing it. */
691 int w32_BDF_to_x_font (char *file, char* xstr, int len)
693 HANDLE hfile, hfilemap;
694 BY_HANDLE_FILE_INFORMATION fileinfo;
695 unsigned char *font, *start, *p, *q;
696 int flag, size, retval = 0;
698 hfile = CreateFile (file, GENERIC_READ, FILE_SHARE_READ, NULL,
699 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
700 if (hfile == INVALID_HANDLE_VALUE) return 0;
701 if (!GetFileInformationByHandle(hfile, &fileinfo) ||
702 (fileinfo.nFileSizeHigh != 0) ||
703 (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX))
705 CloseHandle (hfile);
706 return 0;
708 size = fileinfo.nFileSizeLow;
710 hfilemap = CreateFileMapping (hfile, NULL, PAGE_READONLY, 0, 0, NULL);
711 if (hfilemap == INVALID_HANDLE_VALUE)
713 CloseHandle (hfile);
714 return 0;
717 font = MapViewOfFile (hfilemap, FILE_MAP_READ, 0, 0, 0);
718 if (!font)
720 CloseHandle (hfile);
721 CloseHandle (hfilemap);
722 return 0;
724 start = font;
726 flag = proceed_file_line ("FONT ", start, &size, &p, &q);
727 if (flag)
729 /* If font provides a description of itself, check it is a
730 full XLFD before accepting it. */
731 int count = 0;
732 char *s;
734 for (s = p; s < q; s++)
735 if (*s == '\n')
736 break;
737 else if (*s == '-')
738 count++;
739 if (count == 14 && q - p - 1 <= len)
741 strncpy (xstr, p, q-p-1);
742 xstr[q-p-1] = '\0';
743 /* Files may have DOS line ends (ie still ^M on end). */
744 if (iscntrl(xstr[q-p-2]))
745 xstr[q-p-2] = '\0';
747 retval = 1;
750 CloseHandle (hfile);
751 CloseHandle (hfilemap);
752 return retval;