*** empty log message ***
[emacs.git] / src / w32bdf.c
blobe287f499ec1e34ab5bae463819c24d10d5120aef
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 "fontset.h"
29 #include "blockinput.h"
30 #include "w32gui.h"
31 #include "w32term.h"
32 #include "w32bdf.h"
34 #define min(a, b) ((a) < (b) ? (a) : (b))
35 #define max(a, b) ((a) > (b) ? (a) : (b))
37 /* Portion of GDI Objects which the font cache is allowed to use. This
38 can be quite high, since the font cache is the only part of Emacs
39 that uses a large number of GDI objects, but there should still be
40 some GDI objects reserved for other uses. */
41 #define CACHE_GDI_ALLOWANCE 9 / 10
43 void w32_free_bdf_font(bdffont *fontp);
44 bdffont *w32_init_bdf_font(char *filename);
46 static int
47 search_file_line(char *key, char *start, int len, char **val, char **next)
49 int linelen;
50 unsigned char *p, *q;
52 p = memchr(start, '\n', len);
53 if (!p) return -1;
54 for (;start < p;start++)
56 if ((*start != ' ') || (*start != '\t')) break;
58 linelen = p - start + 1;
59 *next = p + 1;
60 if (strncmp(start, key, min(strlen(key), linelen)) == 0)
62 *val = start + strlen(key);
63 return 1;
66 return 0;
69 static int
70 proceed_file_line(char *key, char *start, int *len, char **val, char **next)
72 int flag = 0;
74 do {
75 flag = search_file_line(key, start, *len, val, next);
76 *len -= (int)(*next - start);
77 start = *next;
78 }while(flag == 0);
80 if (flag == -1) return 0;
81 return 1;
84 char*
85 get_quoted_string(char *start, char *end)
87 char *p, *q, *result;
89 p = memchr(start, '\"', end - start);
90 q = 0;
92 if (!p) return NULL;
93 p++;
94 q = memchr(p, '\"', end - q);
95 if (!q) return NULL;
97 result = (char*) xmalloc(q - p + 1);
99 memcpy(result, p, q - p);
100 result[q - p] = '\0';
102 return result;
105 static int
106 set_bdf_font_info(bdffont *fontp)
108 unsigned char *start, *p, *q;
109 int len, flag;
110 int bbw, bbh, bbx, bby;
111 int val1;
113 len = fontp->size;
114 start = fontp->font;
116 fontp->yoffset = 0;
117 fontp->relative_compose = 0;
118 fontp->default_ascent = 0;
119 fontp->registry = NULL;
120 fontp->encoding = NULL;
121 fontp->slant = NULL;
122 /* fontp->width = NULL; */
124 flag = proceed_file_line("FONTBOUNDINGBOX", start, &len, &p, &q);
125 if (!flag) return 0;
126 bbw = strtol(p, &start, 10);
127 p = start;
128 bbh = strtol(p, &start, 10);
129 p = start;
130 bbx = strtol(p, &start, 10);
131 p = start;
132 bby = strtol(p, &start, 10);
134 fontp->llx = bbx;
135 fontp->lly = bby;
136 fontp->urx = bbw + bbx;
137 fontp->ury = bbh + bby;
138 fontp->width = bbw;
139 fontp->height = bbh;
140 start = q;
141 flag = proceed_file_line("STARTPROPERTIES", start, &len, &p, &q);
142 if (!flag) return 1;
144 flag = 0;
146 do {
147 start = q;
148 if (search_file_line("PIXEL_SIZE", start, len, &p, &q) == 1)
150 val1 = atoi(p);
151 fontp->pixsz = val1;
153 else if (search_file_line("FONT_ASCENT", start, len, &p, &q) == 1)
155 val1 = atoi(p);
156 fontp->ury = val1;
158 else if (search_file_line("FONT_DESCENT", start, len, &p, &q) == 1)
160 val1 = atoi(p);
161 fontp->lly = -val1;
163 else if (search_file_line("_MULE_BASELINE_OFFSET", start, len, &p, &q) == 1)
165 val1 = atoi(p);
166 fontp->yoffset = val1;
168 else if (search_file_line("_MULE_RELATIVE_COMPOSE", start, len, &p, &q) == 1)
170 val1 = atoi(p);
171 fontp->relative_compose = val1;
173 else if (search_file_line("_MULE_DEFAULT_ASCENT", start, len, &p, &q) == 1)
175 val1 = atoi(p);
176 fontp->default_ascent = val1;
178 else if (search_file_line("CHARSET_REGISTRY", start, len, &p, &q) == 1)
180 fontp->registry = get_quoted_string(p, q);
182 else if (search_file_line("CHARSET_ENCODING", start, len, &p, &q) == 1)
184 fontp->encoding = get_quoted_string(p, q);
186 else if (search_file_line("SLANT", start, len, &p, &q) == 1)
188 fontp->slant = get_quoted_string(p, q);
191 else if (search_file_line("SETWIDTH_NAME", start, len, &p, &q) == 1)
193 fontp->width = get_quoted_string(p, q);
196 else
198 flag = search_file_line("ENDPROPERTIES", start, len, &p, &q);
200 if (flag == -1) return 0;
201 len -= (q - start);
202 }while(flag == 0);
203 start = q;
204 flag = proceed_file_line("CHARS", start, &len, &p, &q);
205 if (!flag) return 0;
206 fontp->seeked = q;
208 return 1;
211 bdffont*
212 w32_init_bdf_font(char *filename)
214 HANDLE hfile, hfilemap;
215 bdffont *bdffontp;
216 unsigned char *font;
217 BY_HANDLE_FILE_INFORMATION fileinfo;
218 int i;
220 hfile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
221 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
222 if (hfile == INVALID_HANDLE_VALUE) return NULL;
223 if (!GetFileInformationByHandle(hfile, &fileinfo) ||
224 (fileinfo.nFileSizeHigh != 0) ||
225 (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX))
227 CloseHandle(hfile);
228 error("Fail to open BDF file.");
230 hfilemap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL);
231 if (hfilemap == INVALID_HANDLE_VALUE)
233 CloseHandle(hfile);
234 error("Can't map font.");
237 font = MapViewOfFile(hfilemap, FILE_MAP_READ, 0, 0, 0);
239 if (!font)
241 CloseHandle(hfile);
242 CloseHandle(hfilemap);
243 error("Can't view font.");
246 bdffontp = (bdffont *) xmalloc(sizeof(bdffont));
248 for(i = 0;i < BDF_FIRST_OFFSET_TABLE;i++)
249 bdffontp->chtbl[i] = NULL;
250 bdffontp->size = fileinfo.nFileSizeLow;
251 bdffontp->font = font;
252 bdffontp->hfile = hfile;
253 bdffontp->hfilemap = hfilemap;
254 bdffontp->filename = (char*) xmalloc(strlen(filename) + 1);
255 strcpy(bdffontp->filename, filename);
257 if (!set_bdf_font_info(bdffontp))
259 w32_free_bdf_font(bdffontp);
260 error("Invalid BDF font!");
262 return bdffontp;
265 void
266 w32_free_bdf_font(bdffont *fontp)
268 int i, j;
269 font_char *pch;
270 cache_bitmap *pcb;
272 UnmapViewOfFile(fontp->hfilemap);
273 CloseHandle(fontp->hfilemap);
274 CloseHandle(fontp->hfile);
276 if (fontp->registry) xfree(fontp->registry);
277 if (fontp->encoding) xfree(fontp->encoding);
278 if (fontp->slant) xfree(fontp->slant);
279 /* if (fontp->width) xfree(fontp->width); */
281 xfree(fontp->filename);
282 for(i = 0;i < BDF_FIRST_OFFSET_TABLE;i++)
284 pch = fontp->chtbl[i];
285 if (pch)
287 for (j = 0;j < BDF_SECOND_OFFSET_TABLE;j++)
289 pcb = pch[j].pcbmp;
290 if (pcb) pcb->psrc = NULL;
292 xfree(pch);
295 xfree(fontp);
298 static font_char*
299 get_cached_font_char(bdffont *fontp, int index)
301 font_char *pch, *result;
302 int i;
304 if (index > 0xffff)
305 return NULL;
307 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)];
308 if (!pch)
309 return NULL;
310 result = &pch[BDF_SECOND_OFFSET(index)];
312 if (!result->offset) return NULL;
314 return result;
317 static font_char*
318 cache_char_offset(bdffont *fontp, int index, unsigned char *offset)
320 font_char *pch, *result;
321 int i;
323 if (index > 0xffff)
324 return NULL;
326 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)];
327 if (!pch)
329 pch = fontp->chtbl[BDF_FIRST_OFFSET(index)] =
330 (font_char*) xmalloc(sizeof(font_char) *
331 BDF_SECOND_OFFSET_TABLE);
332 memset(pch, 0, sizeof(font_char) * BDF_SECOND_OFFSET_TABLE);
335 result = &pch[BDF_SECOND_OFFSET(index)];
336 result->offset = offset;
338 return result;
341 static font_char*
342 seek_char(bdffont *fontp, int index)
344 font_char *result;
345 int len, flag, font_index;
346 unsigned char *start, *p, *q;
348 if (!fontp->seeked) return NULL;
350 start = fontp->seeked;
351 len = fontp->size - (start - fontp->font);
353 do {
354 flag = proceed_file_line("ENCODING", start, &len, &p, &q);
355 if (!flag)
357 fontp->seeked = NULL;
358 return NULL;
360 font_index = atoi(p);
361 result = cache_char_offset(fontp, font_index, q);
362 if (!result) return NULL;
364 start = result->offset;
365 } while (font_index != index);
366 fontp->seeked = start;
368 return result;
371 #define GET_HEX_VAL(x) ((isdigit(x)) ? ((x) - '0') : \
372 (((x) >= 'A') && ((x) <= 'Z')) ? ((x) - 'A' + 10) : \
373 (((x) >= 'a') && ((x) <= 'z')) ? ((x) - 'a' + 10) : \
374 (-1))
377 w32_get_bdf_glyph(bdffont *fontp, int index, int size, glyph_struct *glyph)
379 font_char *pch;
380 unsigned char *start, *p, *q, *bitmapp;
381 unsigned char val1, val2;
382 int i, j, len, flag;
384 pch = get_cached_font_char(fontp, index);
385 if (!pch)
387 pch = seek_char(fontp, index);
388 if (!pch)
389 return 0;
392 start = pch->offset;
394 if ((size == 0) && pch->pcbmp)
396 glyph->metric = pch->pcbmp->metric;
397 return 1;
400 len = fontp->size - (start - fontp->font);
402 flag = proceed_file_line("DWIDTH", start, &len, &p, &q);
403 if (!flag)
404 return 0;
405 glyph->metric.dwidth = atoi(p);
407 start = q;
408 flag = proceed_file_line("BBX", start, &len, &p, &q);
409 if (!flag)
410 return 0;
411 glyph->metric.bbw = strtol(p, &start, 10);
412 p = start;
413 glyph->metric.bbh = strtol(p, &start, 10);
414 p = start;
415 glyph->metric.bbox = strtol(p, &start, 10);
416 p = start;
417 glyph->metric.bboy = strtol(p, &start, 10);
419 if (size == 0) return 1;
421 start = q;
422 flag = proceed_file_line("BITMAP", start, &len, &p, &q);
423 if (!flag)
424 return 0;
426 p = q;
427 bitmapp = glyph->bitmap;
428 for(i = 0;i < glyph->metric.bbh;i++)
430 q = memchr(p, '\n', len);
431 if (!q) return 0;
432 for(j = 0;((q > p) && (j < ((glyph->metric.bbw + 7) / 8 )));j++)
434 val1 = GET_HEX_VAL(*p);
435 if (val1 == -1) return 0;
436 p++;
437 val2 = GET_HEX_VAL(*p);
438 if (val2 == -1) return 0;
439 p++;
440 size--;
441 if (size <= 0) return 0;
442 /* NAND Operation. */
443 *bitmapp++ = (unsigned char)~((val1 << 4) | val2);
445 /* CreateBitmap requires WORD alignment. */
446 if (j % 2)
448 *bitmapp++ = 0xff;
450 p = q + 1;
453 return 1;
456 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
458 static
459 cache_bitmap*
460 get_bitmap_with_cache(bdffont *fontp, int index)
462 int bitmap_size;
463 font_char *pch;
464 cache_bitmap* pcb;
465 HBITMAP hbmp;
466 glyph_struct glyph;
467 static cache_bitmap cached_bitmap_slots[BDF_FONT_CACHE_SIZE];
468 static int cache_in_slot = 0; /* the next slot to use */
469 static int cache_out_slot = 0; /* the last slot allocated */
470 static int cache_occupancy = 0; /* current cache occupancy */
471 static int cache_limit = BDF_FONT_CACHE_SIZE; /* allowed maximum occupancy */
473 pch = get_cached_font_char(fontp, index);
474 if (pch)
476 pcb = pch->pcbmp;
477 if (pcb) return pcb;
480 bitmap_size = ((fontp->urx - fontp->llx) / 8 + 2) * (fontp->ury - fontp->lly)
481 + 256;
482 glyph.bitmap = (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size);
484 if (!w32_get_bdf_glyph(fontp, index, bitmap_size, &glyph))
485 return NULL;
487 pch = get_cached_font_char(fontp, index);
488 if (!pch) return NULL;
490 hbmp = CreateBitmap(glyph.metric.bbw, glyph.metric.bbh, 1, 1, glyph.bitmap);
492 /* if bitmap allocation fails reduce the limit of the occupancy so
493 that we can hope it will not happen again. */
494 if (hbmp == NULL)
495 cache_limit = cache_occupancy * CACHE_GDI_ALLOWANCE;
497 /* if cache occupancy reaches at the limit release some cache slots */
498 if (cache_occupancy >= cache_limit)
500 register int size_to_clear = cache_limit * BDF_FONT_CLEAR_SIZE
501 / BDF_FONT_CACHE_SIZE;
502 for (; size_to_clear; size_to_clear--,
503 cache_out_slot = NEXT_CACHE_SLOT(cache_out_slot))
505 register cache_bitmap *p = &cached_bitmap_slots[cache_out_slot];
506 if (p->psrc)
508 DeleteObject(p->hbmp);
509 p->psrc->pcbmp = NULL;
510 p->psrc = NULL;
511 cache_occupancy--;
516 if (hbmp == NULL)
517 hbmp = CreateBitmap (glyph.metric.bbw, glyph.metric.bbh,
518 1, 1, glyph.bitmap);
520 pcb = &cached_bitmap_slots[cache_in_slot];
522 pcb->psrc = pch;
523 pcb->metric = glyph.metric;
524 pcb->hbmp = hbmp;
526 pch->pcbmp = pcb;
528 cache_in_slot = NEXT_CACHE_SLOT(cache_in_slot);
529 cache_occupancy++;
531 return pcb;
535 w32_BDF_TextOut(bdffont *fontp, HDC hdc, int left,
536 int top, unsigned char *text, int dim, int bytelen,
537 int fixed_pitch_size)
539 int index, btop;
540 unsigned char *textp;
541 HDC hCompatDC = 0;
542 cache_bitmap *pcb;
543 HBITMAP hBMP;
544 HBRUSH hFgBrush, hOrgBrush;
545 HANDLE horgobj = 0;
546 UINT textalign;
547 int flag = 0;
549 hCompatDC = CreateCompatibleDC(hdc);
551 textalign = GetTextAlign(hdc);
553 SaveDC(hdc);
555 hFgBrush = CreateSolidBrush(GetTextColor(hdc));
556 hOrgBrush = SelectObject(hdc, hFgBrush);
557 SetTextColor(hdc, RGB(0, 0, 0));
558 SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
560 textp = text;
561 while(bytelen > 0)
563 if (dim == 1)
565 index = *textp++;
566 bytelen--;
568 else
570 bytelen -= 2;
571 if (bytelen < 0) break;
572 index = MAKELENDSHORT(textp[1], textp[0]);
573 textp += 2;
575 pcb = get_bitmap_with_cache(fontp, index);
576 if (!pcb)
578 if (horgobj)
580 SelectObject(hCompatDC, horgobj);
581 DeleteObject(hBMP);
583 DeleteDC(hCompatDC);
584 return 0;
586 hBMP = pcb->hbmp;
588 if (textalign & TA_BASELINE)
589 btop = top - (pcb->metric.bbh + pcb->metric.bboy);
590 else if (textalign & TA_BOTTOM)
591 btop = top - pcb->metric.bbh;
592 else
593 btop = top;
595 if (horgobj)
596 SelectObject(hCompatDC, hBMP);
597 else
598 horgobj = SelectObject(hCompatDC, hBMP);
599 #if 0
600 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, SRCCOPY);
601 #else
602 BitBlt(hdc, left, btop, pcb->metric.bbw, pcb->metric.bbh, hCompatDC, 0, 0, 0xB8074A);
603 #endif
604 if (fixed_pitch_size)
605 left += fixed_pitch_size;
606 else
607 left += pcb->metric.dwidth;
609 SelectObject(hCompatDC, horgobj);
610 SelectObject(hdc, hOrgBrush);
611 DeleteObject(hFgBrush);
612 DeleteDC(hCompatDC);
613 RestoreDC(hdc, -1);
615 return 1;
618 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
619 int size, char* filename)
621 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
622 struct font_info *fontp;
623 XFontStruct *font;
624 bdffont* bdf_font;
626 bdf_font = w32_init_bdf_font (filename);
628 if (!bdf_font) return NULL;
630 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
632 font->bdf = bdf_font;
633 font->hfont = 0;
635 /* Do we need to create the table? */
636 if (dpyinfo->font_table_size == 0)
638 dpyinfo->font_table_size = 16;
639 dpyinfo->font_table
640 = (struct font_info *) xmalloc (dpyinfo->font_table_size
641 * sizeof (struct font_info));
643 /* Do we need to grow the table? */
644 else if (dpyinfo->n_fonts
645 >= dpyinfo->font_table_size)
647 dpyinfo->font_table_size *= 2;
648 dpyinfo->font_table
649 = (struct font_info *) xrealloc (dpyinfo->font_table,
650 (dpyinfo->font_table_size
651 * sizeof (struct font_info)));
654 fontp = dpyinfo->font_table + dpyinfo->n_fonts;
656 /* Now fill in the slots of *FONTP. */
657 BLOCK_INPUT;
658 fontp->font = font;
659 fontp->font_idx = dpyinfo->n_fonts;
660 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
661 bcopy (fontname, fontp->name, strlen (fontname) + 1);
662 fontp->full_name = fontp->name;
663 fontp->size = FONT_WIDTH (font);
664 fontp->height = FONT_HEIGHT (font);
666 /* The slot `encoding' specifies how to map a character
667 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
668 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
669 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
670 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
671 2:0xA020..0xFF7F). For the moment, we don't know which charset
672 uses this font. So, we set informatoin in fontp->encoding[1]
673 which is never used by any charset. If mapping can't be
674 decided, set FONT_ENCODING_NOT_DECIDED. */
675 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
676 fontp->baseline_offset = bdf_font->yoffset;
677 fontp->relative_compose = bdf_font->relative_compose;
678 fontp->default_ascent = bdf_font->default_ascent;
680 UNBLOCK_INPUT;
681 dpyinfo->n_fonts++;
682 return fontp;
685 /* Check a file for an XFLD string describing it. */
686 int w32_BDF_to_x_font (char *file, char* xstr, int len)
688 HANDLE hfile, hfilemap;
689 BY_HANDLE_FILE_INFORMATION fileinfo;
690 unsigned char *font, *start, *p, *q;
691 int flag, size, retval = 0;
693 hfile = CreateFile (file, GENERIC_READ, FILE_SHARE_READ, NULL,
694 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
695 if (hfile == INVALID_HANDLE_VALUE) return 0;
696 if (!GetFileInformationByHandle(hfile, &fileinfo) ||
697 (fileinfo.nFileSizeHigh != 0) ||
698 (fileinfo.nFileSizeLow > BDF_FILE_SIZE_MAX))
700 CloseHandle (hfile);
701 return 0;
703 size = fileinfo.nFileSizeLow;
705 hfilemap = CreateFileMapping (hfile, NULL, PAGE_READONLY, 0, 0, NULL);
706 if (hfilemap == INVALID_HANDLE_VALUE)
708 CloseHandle (hfile);
709 return 0;
712 font = MapViewOfFile (hfilemap, FILE_MAP_READ, 0, 0, 0);
713 if (!font)
715 CloseHandle (hfile);
716 CloseHandle (hfilemap);
717 return 0;
719 start = font;
721 flag = proceed_file_line ("FONT ", start, &size, &p, &q);
722 if (flag)
724 /* If font provides a description of itself, check it is a
725 full XLFD before accepting it. */
726 int count = 0;
727 char *s;
729 for (s = p; s < q; s++)
730 if (*s == '\n')
731 break;
732 else if (*s == '-')
733 count++;
734 if (count == 14 && q - p - 1 <= len)
736 strncpy (xstr, p, q-p-1);
737 xstr[q-p-1] = '\0';
738 /* Files may have DOS line ends (ie still ^M on end). */
739 if (iscntrl(xstr[q-p-2]))
740 xstr[q-p-2] = '\0';
742 retval = 1;
745 CloseHandle (hfile);
746 CloseHandle (hfilemap);
747 return retval;