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)
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
29 #include "dispextern.h"
31 #include "blockinput.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
);
49 search_file_line(char *key
, char *start
, int len
, char **val
, char **next
)
54 p
= memchr(start
, '\n', len
);
56 for (;start
< p
;start
++)
58 if ((*start
!= ' ') || (*start
!= '\t')) break;
60 linelen
= p
- start
+ 1;
62 if (strncmp(start
, key
, min(strlen(key
), linelen
)) == 0)
64 *val
= start
+ strlen(key
);
72 proceed_file_line(char *key
, char *start
, int *len
, char **val
, char **next
)
77 flag
= search_file_line(key
, start
, *len
, val
, next
);
78 *len
-= (int)(*next
- start
);
82 if (flag
== -1) return 0;
87 get_quoted_string(char *start
, char *end
)
91 p
= memchr(start
, '\"', end
- start
);
96 q
= memchr(p
, '\"', end
- q
);
99 result
= (char*) xmalloc(q
- p
+ 1);
101 memcpy(result
, p
, q
- p
);
102 result
[q
- p
] = '\0';
108 set_bdf_font_info(bdffont
*fontp
)
110 unsigned char *start
, *p
, *q
;
112 int bbw
, bbh
, bbx
, bby
;
119 fontp
->relative_compose
= 0;
120 fontp
->default_ascent
= 0;
121 fontp
->registry
= NULL
;
122 fontp
->encoding
= NULL
;
124 /* fontp->width = NULL; */
126 flag
= proceed_file_line("FONTBOUNDINGBOX", start
, &len
, &p
, &q
);
128 bbw
= strtol(p
, &start
, 10);
130 bbh
= strtol(p
, &start
, 10);
132 bbx
= strtol(p
, &start
, 10);
134 bby
= strtol(p
, &start
, 10);
138 fontp
->urx
= bbw
+ bbx
;
139 fontp
->ury
= bbh
+ bby
;
143 flag
= proceed_file_line("STARTPROPERTIES", start
, &len
, &p
, &q
);
150 if (search_file_line("PIXEL_SIZE", start
, len
, &p
, &q
) == 1)
155 else if (search_file_line("FONT_ASCENT", start
, len
, &p
, &q
) == 1)
160 else if (search_file_line("FONT_DESCENT", start
, len
, &p
, &q
) == 1)
165 else if (search_file_line("_MULE_BASELINE_OFFSET", start
, len
, &p
, &q
) == 1)
168 fontp
->yoffset
= val1
;
170 else if (search_file_line("_MULE_RELATIVE_COMPOSE", start
, len
, &p
, &q
) == 1)
173 fontp
->relative_compose
= val1
;
175 else if (search_file_line("_MULE_DEFAULT_ASCENT", start
, len
, &p
, &q
) == 1)
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);
200 flag
= search_file_line("ENDPROPERTIES", start
, len
, &p
, &q
);
202 if (flag
== -1) return 0;
206 flag
= proceed_file_line("CHARS", start
, &len
, &p
, &q
);
214 w32_init_bdf_font(char *filename
)
216 HANDLE hfile
, hfilemap
;
219 BY_HANDLE_FILE_INFORMATION fileinfo
;
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
))
230 error("Fail to open BDF file.");
232 hfilemap
= CreateFileMapping(hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
233 if (hfilemap
== INVALID_HANDLE_VALUE
)
236 error("Can't map font.");
239 font
= MapViewOfFile(hfilemap
, FILE_MAP_READ
, 0, 0, 0);
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!");
268 w32_free_bdf_font(bdffont
*fontp
)
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
];
289 for (j
= 0;j
< BDF_SECOND_OFFSET_TABLE
;j
++)
292 if (pcb
) pcb
->psrc
= NULL
;
301 get_cached_font_char(bdffont
*fontp
, int index
)
303 font_char
*pch
, *result
;
309 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
312 result
= &pch
[BDF_SECOND_OFFSET(index
)];
314 if (!result
->offset
) return NULL
;
320 cache_char_offset(bdffont
*fontp
, int index
, unsigned char *offset
)
322 font_char
*pch
, *result
;
328 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
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
;
344 seek_char(bdffont
*fontp
, int index
)
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
);
356 flag
= proceed_file_line("ENCODING", start
, &len
, &p
, &q
);
359 fontp
->seeked
= 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
;
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) : \
379 w32_get_bdf_glyph(bdffont
*fontp
, int index
, int size
, glyph_struct
*glyph
)
382 unsigned char *start
, *p
, *q
, *bitmapp
;
383 unsigned char val1
, val2
;
386 pch
= get_cached_font_char(fontp
, index
);
389 pch
= seek_char(fontp
, index
);
396 if ((size
== 0) && pch
->pcbmp
)
398 glyph
->metric
= pch
->pcbmp
->metric
;
402 len
= fontp
->size
- (start
- fontp
->font
);
404 flag
= proceed_file_line("DWIDTH", start
, &len
, &p
, &q
);
407 glyph
->metric
.dwidth
= atoi(p
);
410 flag
= proceed_file_line("BBX", start
, &len
, &p
, &q
);
413 glyph
->metric
.bbw
= strtol(p
, &start
, 10);
415 glyph
->metric
.bbh
= strtol(p
, &start
, 10);
417 glyph
->metric
.bbox
= strtol(p
, &start
, 10);
419 glyph
->metric
.bboy
= strtol(p
, &start
, 10);
421 if (size
== 0) return 1;
424 flag
= proceed_file_line("BITMAP", start
, &len
, &p
, &q
);
429 bitmapp
= glyph
->bitmap
;
430 for(i
= 0;i
< glyph
->metric
.bbh
;i
++)
432 q
= memchr(p
, '\n', len
);
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;
439 val2
= GET_HEX_VAL(*p
);
440 if (val2
== -1) return 0;
443 if (size
<= 0) return 0;
444 /* NAND Operation. */
445 *bitmapp
++ = (unsigned char)~((val1
<< 4) | val2
);
447 /* CreateBitmap requires WORD alignment. */
458 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
462 get_bitmap_with_cache(bdffont
*fontp
, int index
)
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
);
482 bitmap_size
= ((fontp
->urx
- fontp
->llx
) / 8 + 2) * (fontp
->ury
- fontp
->lly
)
484 glyph
.bitmap
= (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size
);
486 if (!w32_get_bdf_glyph(fontp
, index
, bitmap_size
, &glyph
))
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. */
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
];
510 DeleteObject(p
->hbmp
);
511 p
->psrc
->pcbmp
= NULL
;
519 hbmp
= CreateBitmap (glyph
.metric
.bbw
, glyph
.metric
.bbh
,
522 pcb
= &cached_bitmap_slots
[cache_in_slot
];
525 pcb
->metric
= glyph
.metric
;
530 cache_in_slot
= NEXT_CACHE_SLOT(cache_in_slot
);
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
)
542 unsigned char *textp
;
546 HBRUSH hFgBrush
, hOrgBrush
;
551 hCompatDC
= CreateCompatibleDC(hdc
);
553 textalign
= GetTextAlign(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));
573 if (bytelen
< 0) break;
574 index
= MAKELENDSHORT(textp
[1], textp
[0]);
577 pcb
= get_bitmap_with_cache(fontp
, index
);
582 SelectObject(hCompatDC
, horgobj
);
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
;
598 SelectObject(hCompatDC
, hBMP
);
600 horgobj
= SelectObject(hCompatDC
, hBMP
);
602 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, SRCCOPY
);
604 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, 0xB8074A);
606 if (fixed_pitch_size
)
607 left
+= fixed_pitch_size
;
609 left
+= pcb
->metric
.dwidth
;
611 SelectObject(hCompatDC
, horgobj
);
612 SelectObject(hdc
, hOrgBrush
);
613 DeleteObject(hFgBrush
);
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
;
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
;
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;
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;
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. */
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
;
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
))
708 size
= fileinfo
.nFileSizeLow
;
710 hfilemap
= CreateFileMapping (hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
711 if (hfilemap
== INVALID_HANDLE_VALUE
)
717 font
= MapViewOfFile (hfilemap
, FILE_MAP_READ
, 0, 0, 0);
721 CloseHandle (hfilemap
);
726 flag
= proceed_file_line ("FONT ", start
, &size
, &p
, &q
);
729 /* If font provides a description of itself, check it is a
730 full XLFD before accepting it. */
734 for (s
= p
; s
< q
; s
++)
739 if (count
== 14 && q
- p
- 1 <= len
)
741 strncpy (xstr
, p
, q
-p
-1);
743 /* Files may have DOS line ends (ie still ^M on end). */
744 if (iscntrl(xstr
[q
-p
-2]))
751 CloseHandle (hfilemap
);