("latin-1-prefix"): Change ~s to give \e,A'\e(B and
[emacs.git] / src / w32bdf.c
blobc41ecd07220f40221f19ef33f321eccb7c137f64
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 char *p;
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 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;
349 char *p, *q;
351 if (!fontp->seeked) return NULL;
353 start = fontp->seeked;
354 len = fontp->size - (start - fontp->font);
356 do {
357 flag = proceed_file_line("ENCODING", start, &len, &p, &q);
358 if (!flag)
360 fontp->seeked = NULL;
361 return NULL;
363 font_index = atoi(p);
364 result = cache_char_offset(fontp, font_index, q);
365 if (!result) return NULL;
367 start = result->offset;
368 } while (font_index != index);
369 fontp->seeked = start;
371 return result;
374 #define GET_HEX_VAL(x) ((isdigit(x)) ? ((x) - '0') : \
375 (((x) >= 'A') && ((x) <= 'Z')) ? ((x) - 'A' + 10) : \
376 (((x) >= 'a') && ((x) <= 'z')) ? ((x) - 'a' + 10) : \
377 (-1))
380 w32_get_bdf_glyph(bdffont *fontp, int index, int size, glyph_struct *glyph)
382 font_char *pch;
383 unsigned char *start, *bitmapp;
384 char *p, *q;
385 char val1, val2;
386 int i, j, len, flag;
388 pch = get_cached_font_char(fontp, index);
389 if (!pch)
391 pch = seek_char(fontp, index);
392 if (!pch)
393 return 0;
396 start = pch->offset;
398 if ((size == 0) && pch->pcbmp)
400 glyph->metric = pch->pcbmp->metric;
401 return 1;
404 len = fontp->size - (start - fontp->font);
406 flag = proceed_file_line("DWIDTH", start, &len, &p, &q);
407 if (!flag)
408 return 0;
409 glyph->metric.dwidth = atoi(p);
411 start = q;
412 flag = proceed_file_line("BBX", start, &len, &p, &q);
413 if (!flag)
414 return 0;
415 glyph->metric.bbw = strtol(p, &start, 10);
416 p = start;
417 glyph->metric.bbh = strtol(p, &start, 10);
418 p = start;
419 glyph->metric.bbox = strtol(p, &start, 10);
420 p = start;
421 glyph->metric.bboy = strtol(p, &start, 10);
423 if (size == 0) return 1;
425 start = q;
426 flag = proceed_file_line("BITMAP", start, &len, &p, &q);
427 if (!flag)
428 return 0;
430 p = q;
431 bitmapp = glyph->bitmap;
432 for(i = 0;i < glyph->metric.bbh;i++)
434 q = memchr(p, '\n', len);
435 if (!q) return 0;
436 for(j = 0;((q > p) && (j < ((glyph->metric.bbw + 7) / 8 )));j++)
438 val1 = GET_HEX_VAL(*p);
439 if (val1 == -1) return 0;
440 p++;
441 val2 = GET_HEX_VAL(*p);
442 if (val2 == -1) return 0;
443 p++;
444 size--;
445 if (size <= 0) return 0;
446 /* NAND Operation. */
447 *bitmapp++ = (unsigned char)~((val1 << 4) | val2);
449 /* CreateBitmap requires WORD alignment. */
450 if (j % 2)
452 *bitmapp++ = 0xff;
454 p = q + 1;
457 return 1;
460 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
462 static
463 cache_bitmap*
464 get_bitmap_with_cache(bdffont *fontp, int index)
466 int bitmap_size;
467 font_char *pch;
468 cache_bitmap* pcb;
469 HBITMAP hbmp;
470 glyph_struct glyph;
471 static cache_bitmap cached_bitmap_slots[BDF_FONT_CACHE_SIZE];
472 static int cache_in_slot = 0; /* the next slot to use */
473 static int cache_out_slot = 0; /* the last slot allocated */
474 static int cache_occupancy = 0; /* current cache occupancy */
475 static int cache_limit = BDF_FONT_CACHE_SIZE; /* allowed maximum occupancy */
477 pch = get_cached_font_char(fontp, index);
478 if (pch)
480 pcb = pch->pcbmp;
481 if (pcb) return pcb;
484 bitmap_size = ((fontp->urx - fontp->llx) / 8 + 2) * (fontp->ury - fontp->lly)
485 + 256;
486 glyph.bitmap = (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size);
488 if (!w32_get_bdf_glyph(fontp, index, bitmap_size, &glyph))
489 return NULL;
491 pch = get_cached_font_char(fontp, index);
492 if (!pch) return NULL;
494 hbmp = CreateBitmap(glyph.metric.bbw, glyph.metric.bbh, 1, 1, glyph.bitmap);
496 /* if bitmap allocation fails reduce the limit of the occupancy so
497 that we can hope it will not happen again. */
498 if (hbmp == NULL)
499 cache_limit = cache_occupancy * CACHE_GDI_ALLOWANCE;
501 /* if cache occupancy reaches at the limit release some cache slots */
502 if (cache_occupancy >= cache_limit)
504 register int size_to_clear = cache_limit * BDF_FONT_CLEAR_SIZE
505 / BDF_FONT_CACHE_SIZE;
506 for (; size_to_clear; size_to_clear--,
507 cache_out_slot = NEXT_CACHE_SLOT(cache_out_slot))
509 register cache_bitmap *p = &cached_bitmap_slots[cache_out_slot];
510 if (p->psrc)
512 DeleteObject(p->hbmp);
513 p->psrc->pcbmp = NULL;
514 p->psrc = NULL;
515 cache_occupancy--;
520 if (hbmp == NULL)
521 hbmp = CreateBitmap (glyph.metric.bbw, glyph.metric.bbh,
522 1, 1, glyph.bitmap);
524 pcb = &cached_bitmap_slots[cache_in_slot];
526 pcb->psrc = pch;
527 pcb->metric = glyph.metric;
528 pcb->hbmp = hbmp;
530 pch->pcbmp = pcb;
532 cache_in_slot = NEXT_CACHE_SLOT(cache_in_slot);
533 cache_occupancy++;
535 return pcb;
539 w32_BDF_TextOut(bdffont *fontp, HDC hdc, int left,
540 int top, unsigned char *text, int dim, int bytelen,
541 int fixed_pitch_size)
543 int index, btop;
544 unsigned char *textp;
545 HDC hCompatDC = 0;
546 cache_bitmap *pcb;
547 HBITMAP hBMP;
548 HBRUSH hFgBrush, hOrgBrush;
549 HANDLE horgobj = 0;
550 UINT textalign;
551 int flag = 0;
553 hCompatDC = CreateCompatibleDC(hdc);
555 textalign = GetTextAlign(hdc);
557 SaveDC(hdc);
559 hFgBrush = CreateSolidBrush(GetTextColor(hdc));
560 hOrgBrush = SelectObject(hdc, hFgBrush);
561 SetTextColor(hdc, RGB(0, 0, 0));
562 SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
564 textp = text;
565 while(bytelen > 0)
567 if (dim == 1)
569 index = *textp++;
570 bytelen--;
572 else
574 bytelen -= 2;
575 if (bytelen < 0) break;
576 index = MAKELENDSHORT(textp[1], textp[0]);
577 textp += 2;
579 pcb = get_bitmap_with_cache(fontp, index);
580 if (!pcb)
582 if (horgobj)
584 SelectObject(hCompatDC, horgobj);
585 DeleteObject(hBMP);
587 DeleteDC(hCompatDC);
588 return 0;
590 hBMP = pcb->hbmp;
592 if (textalign & TA_BASELINE)
593 btop = top - (pcb->metric.bbh + pcb->metric.bboy);
594 else if (textalign & TA_BOTTOM)
595 btop = top - pcb->metric.bbh;
596 else
597 btop = top;
599 if (horgobj)
600 SelectObject(hCompatDC, hBMP);
601 else
602 horgobj = SelectObject(hCompatDC, hBMP);
603 #if 0
604 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, SRCCOPY);
605 #else
606 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, 0xB8074A);
607 #endif
608 if (fixed_pitch_size)
609 left += fixed_pitch_size;
610 else
611 left += pcb->metric.dwidth;
613 SelectObject(hCompatDC, horgobj);
614 SelectObject(hdc, hOrgBrush);
615 DeleteObject(hFgBrush);
616 DeleteDC(hCompatDC);
617 RestoreDC(hdc, -1);
619 return 1;
622 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
623 int size, char* filename)
625 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
626 struct font_info *fontp;
627 XFontStruct *font;
628 bdffont* bdf_font;
630 bdf_font = w32_init_bdf_font (filename);
632 if (!bdf_font) return NULL;
634 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
636 font->bdf = bdf_font;
637 font->hfont = 0;
639 /* NTEMACS_TODO: Recognize DBCS fonts. */
640 font->double_byte_p = 0;
642 /* Do we need to create the table? */
643 if (dpyinfo->font_table_size == 0)
645 dpyinfo->font_table_size = 16;
646 dpyinfo->font_table
647 = (struct font_info *) xmalloc (dpyinfo->font_table_size
648 * sizeof (struct font_info));
650 /* Do we need to grow the table? */
651 else if (dpyinfo->n_fonts
652 >= dpyinfo->font_table_size)
654 dpyinfo->font_table_size *= 2;
655 dpyinfo->font_table
656 = (struct font_info *) xrealloc (dpyinfo->font_table,
657 (dpyinfo->font_table_size
658 * sizeof (struct font_info)));
661 fontp = dpyinfo->font_table + dpyinfo->n_fonts;
663 /* Now fill in the slots of *FONTP. */
664 BLOCK_INPUT;
665 fontp->font = font;
666 fontp->font_idx = dpyinfo->n_fonts;
667 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
668 bcopy (fontname, fontp->name, strlen (fontname) + 1);
669 fontp->full_name = fontp->name;
670 fontp->size = FONT_WIDTH (font);
671 fontp->height = FONT_HEIGHT (font);
673 /* The slot `encoding' specifies how to map a character
674 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
675 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
676 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
677 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
678 2:0xA020..0xFF7F). For the moment, we don't know which charset
679 uses this font. So, we set informatoin in fontp->encoding[1]
680 which is never used by any charset. If mapping can't be
681 decided, set FONT_ENCODING_NOT_DECIDED. */
682 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
683 fontp->baseline_offset = bdf_font->yoffset;
684 fontp->relative_compose = bdf_font->relative_compose;
685 fontp->default_ascent = bdf_font->default_ascent;
687 UNBLOCK_INPUT;
688 dpyinfo->n_fonts++;
689 return fontp;
692 /* Check a file for an XFLD string describing it. */
693 int w32_BDF_to_x_font (char *file, char* xstr, int len)
695 HANDLE hfile, hfilemap;
696 BY_HANDLE_FILE_INFORMATION fileinfo;
697 char *font, *start, *p, *q;
698 int flag, size, retval = 0;
700 hfile = CreateFile (file, GENERIC_READ, FILE_SHARE_READ, NULL,
701 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
702 if (hfile == INVALID_HANDLE_VALUE) return 0;
703 if (!GetFileInformationByHandle(hfile, &fileinfo) ||
704 (fileinfo.nFileSizeHigh != 0) ||
705 (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX))
707 CloseHandle (hfile);
708 return 0;
710 size = fileinfo.nFileSizeLow;
712 hfilemap = CreateFileMapping (hfile, NULL, PAGE_READONLY, 0, 0, NULL);
713 if (hfilemap == INVALID_HANDLE_VALUE)
715 CloseHandle (hfile);
716 return 0;
719 font = MapViewOfFile (hfilemap, FILE_MAP_READ, 0, 0, 0);
720 if (!font)
722 CloseHandle (hfile);
723 CloseHandle (hfilemap);
724 return 0;
726 start = font;
728 flag = proceed_file_line ("FONT ", start, &size, &p, &q);
729 if (flag)
731 /* If font provides a description of itself, check it is a
732 full XLFD before accepting it. */
733 int count = 0;
734 char *s;
736 for (s = p; s < q; s++)
737 if (*s == '\n')
738 break;
739 else if (*s == '-')
740 count++;
741 if (count == 14 && q - p - 1 <= len)
743 strncpy (xstr, p, q-p-1);
744 xstr[q-p-1] = '\0';
745 /* Files may have DOS line ends (ie still ^M on end). */
746 if (iscntrl(xstr[q-p-2]))
747 xstr[q-p-2] = '\0';
749 retval = 1;
752 CloseHandle (hfile);
753 CloseHandle (hfilemap);
754 return retval;