1 /* Implementation of BDF font handling on the Microsoft W32 API.
2 Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
22 /* Based heavily on code by H. Miyashita for Meadow (a descendant of
35 #include "dispextern.h"
37 #include "blockinput.h"
43 #define BDF_CODEPOINT_HEAP_INITIAL_SIZE (96 * 10)
44 /* about 96 characters */
45 #define BDF_BITMAP_HEAP_INITIAL_SIZE (64 * 96)
47 HANDLE hbdf_cp_heap
= INVALID_HANDLE_VALUE
;
48 HANDLE hbdf_bmp_heap
= INVALID_HANDLE_VALUE
;
50 void w32_free_bdf_font(bdffont
*fontp
);
51 bdffont
*w32_init_bdf_font(char *filename
);
53 cache_bitmap cached_bitmap_slots
[BDF_FONT_CACHE_SIZE
];
54 cache_bitmap
*pcached_bitmap_latest
= cached_bitmap_slots
;
56 #define FONT_CACHE_SLOT_OVER_P(p) ((p) >= cached_bitmap_slots + BDF_FONT_CACHE_SIZE)
59 search_file_line(char *key
, char *start
, int len
, char **val
, char **next
)
64 p
= memchr(start
, '\n', len
);
66 for (;(unsigned char *)start
< p
;start
++)
68 if ((*start
!= ' ') && (*start
!= '\t')) break;
70 linelen
= (char *) p
- start
+ 1;
72 if (strncmp(start
, key
, min(strlen(key
), linelen
)) == 0)
74 *val
= start
+ strlen(key
);
82 proceed_file_line(char *key
, char *start
, int *len
, char **val
, char **next
)
87 flag
= search_file_line(key
, start
, *len
, val
, next
);
88 *len
-= (int)(*next
- start
);
92 if (flag
== -1) return 0;
97 get_quoted_string(char *start
, char *end
)
101 p
= memchr(start
, '\"', end
- start
);
104 q
= memchr(p
, '\"', end
- p
);
107 result
= (char*) xmalloc(q
- p
+ 1);
109 memcpy(result
, p
, q
- p
);
110 result
[q
- p
] = '\0';
116 set_bdf_font_info(bdffont
*fontp
)
118 unsigned char *start
, *p
, *q
;
120 int bbw
, bbh
, bbx
, bby
;
127 fontp
->relative_compose
= 0;
128 fontp
->default_ascent
= 0;
130 fontp
->registry
= NULL
;
131 fontp
->encoding
= NULL
;
133 /* fontp->width = NULL; */
135 flag
= proceed_file_line("FONTBOUNDINGBOX", start
, &len
,
136 (char **)&p
, (char **)&q
);
138 bbw
= strtol(p
, (char **)&start
, 10);
140 bbh
= strtol(p
, (char **)&start
, 10);
142 bbx
= strtol(p
, (char **)&start
, 10);
144 bby
= strtol(p
, (char **)&start
, 10);
148 fontp
->urx
= bbw
+ bbx
;
149 fontp
->ury
= bbh
+ bby
;
153 flag
= proceed_file_line("STARTPROPERTIES", start
, &len
,
154 (char **)&p
, (char **)&q
);
161 if (search_file_line("PIXEL_SIZE", start
, len
,
162 (char **)&p
, (char **)&q
) == 1)
167 else if (search_file_line("FONT_ASCENT", start
, len
,
168 (char **)&p
, (char **)&q
) == 1)
173 else if (search_file_line("FONT_DESCENT", start
, len
,
174 (char **)&p
, (char **)&q
) == 1)
179 else if (search_file_line("_MULE_BASELINE_OFFSET", start
, len
,
180 (char **)&p
, (char **)&q
) == 1)
183 fontp
->yoffset
= -val1
;
185 else if (search_file_line("_MULE_RELATIVE_COMPOSE", start
, len
,
186 (char **)&p
, (char **)&q
) == 1)
189 fontp
->relative_compose
= val1
;
191 else if (search_file_line("_MULE_DEFAULT_ASCENT", start
, len
,
192 (char **)&p
, (char **)&q
) == 1)
195 fontp
->default_ascent
= val1
;
197 else if (search_file_line("CHARSET_REGISTRY", start
, len
,
198 (char **)&p
, (char **)&q
) == 1)
200 fontp
->registry
= get_quoted_string(p
, q
);
202 else if (search_file_line("CHARSET_ENCODING", start
, len
,
203 (char **)&p
, (char **)&q
) == 1)
205 fontp
->encoding
= get_quoted_string(p
, q
);
207 else if (search_file_line("SLANT", start
, len
,
208 (char **)&p
, (char **)&q
) == 1)
210 fontp
->slant
= get_quoted_string(p
, q
);
213 else if (search_file_line("SETWIDTH_NAME", start, len,
214 (char **)&p, (char **)&q) == 1)
216 fontp->width = get_quoted_string(p, q);
221 flag
= search_file_line("ENDPROPERTIES", start
, len
,
222 (char **)&p
, (char **)&q
);
224 if (flag
== -1) return 0;
228 flag
= proceed_file_line("CHARS", start
, &len
, (char **)&p
, (char **)&q
);
230 fontp
->nchars
= atoi(p
);
237 w32_init_bdf_font(char *filename
)
239 HANDLE hfile
, hfilemap
;
242 BY_HANDLE_FILE_INFORMATION fileinfo
;
245 if (hbdf_cp_heap
== INVALID_HANDLE_VALUE
)
246 hbdf_cp_heap
= HeapCreate(0, BDF_CODEPOINT_HEAP_INITIAL_SIZE
, 0);
247 if (hbdf_bmp_heap
== INVALID_HANDLE_VALUE
)
248 hbdf_bmp_heap
= HeapCreate(0, BDF_BITMAP_HEAP_INITIAL_SIZE
, 0);
250 if (!hbdf_cp_heap
|| !hbdf_bmp_heap
)
251 error("Fail to create heap for BDF");
253 hfile
= CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
254 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
255 if (hfile
== INVALID_HANDLE_VALUE
) return NULL
;
256 if (!GetFileInformationByHandle(hfile
, &fileinfo
) ||
257 (fileinfo
.nFileSizeHigh
!= 0) ||
258 (fileinfo
.nFileSizeLow
> BDF_FILE_SIZE_MAX
))
261 error("Fail to open BDF file");
263 hfilemap
= CreateFileMapping(hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
267 error("Can't map font");
270 font
= MapViewOfFile(hfilemap
, FILE_MAP_READ
, 0, 0, 0);
275 CloseHandle(hfilemap
);
276 error("Can't view font");
279 bdffontp
= (bdffont
*) xmalloc(sizeof(bdffont
));
281 for(i
= 0;i
< BDF_FIRST_OFFSET_TABLE
;i
++)
282 bdffontp
->chtbl
[i
] = NULL
;
283 bdffontp
->size
= fileinfo
.nFileSizeLow
;
284 bdffontp
->font
= font
;
285 bdffontp
->hfile
= hfile
;
286 bdffontp
->hfilemap
= hfilemap
;
287 bdffontp
->filename
= (char*) xmalloc(strlen(filename
) + 1);
288 strcpy(bdffontp
->filename
, filename
);
290 if (!set_bdf_font_info(bdffontp
))
292 w32_free_bdf_font(bdffontp
);
293 error("Invalid BDF font!");
299 w32_free_bdf_font(bdffont
*fontp
)
305 UnmapViewOfFile(fontp
->font
);
306 CloseHandle(fontp
->hfilemap
);
307 CloseHandle(fontp
->hfile
);
309 if (fontp
->registry
) xfree(fontp
->registry
);
310 if (fontp
->encoding
) xfree(fontp
->encoding
);
311 if (fontp
->slant
) xfree(fontp
->slant
);
312 /* if (fontp->width) xfree(fontp->width); */
314 xfree(fontp
->filename
);
315 for(i
= 0;i
< BDF_FIRST_OFFSET_TABLE
;i
++)
317 pch
= fontp
->chtbl
[i
];
320 for (j
= 0;j
< BDF_SECOND_OFFSET_TABLE
;j
++)
326 HeapFree(hbdf_bmp_heap
, 0, pcb
->pbmp
);
330 HeapFree(hbdf_cp_heap
, 0, pch
);
337 get_cached_font_char(bdffont
*fontp
, int index
)
339 font_char
*pch
, *result
;
341 if (!BDF_CODEPOINT_RANGE_COVER_P(index
))
344 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
348 result
= &pch
[BDF_SECOND_OFFSET(index
)];
350 if (!result
->offset
) return NULL
;
356 cache_char_offset(bdffont
*fontp
, int index
, unsigned char *offset
)
358 font_char
*pch
, *result
;
360 if (!BDF_CODEPOINT_RANGE_COVER_P(index
))
363 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
366 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)] =
367 (font_char
*) HeapAlloc(hbdf_cp_heap
,
370 BDF_SECOND_OFFSET_TABLE
);
371 if (!pch
) return NULL
;
372 /* memset(pch, 0, sizeof(font_char) * BDF_SECOND_OFFSET_TABLE); */
375 result
= &pch
[BDF_SECOND_OFFSET(index
)];
376 result
->offset
= offset
;
382 seek_char(bdffont
*fontp
, int index
)
385 int len
, flag
, font_index
;
386 unsigned char *start
, *p
, *q
;
388 if (!fontp
->seeked
) return NULL
;
390 start
= fontp
->seeked
;
391 len
= fontp
->size
- (start
- fontp
->font
);
394 flag
= proceed_file_line("ENCODING", start
, &len
,
395 (char **)&p
, (char **)&q
);
398 fontp
->seeked
= NULL
;
401 font_index
= atoi(p
);
402 result
= cache_char_offset(fontp
, font_index
, q
);
403 if (!result
) return NULL
;
405 start
= result
->offset
;
406 } while (font_index
!= index
);
407 fontp
->seeked
= start
;
413 clear_cached_bitmap_slots()
418 p
= pcached_bitmap_latest
;
419 for (i
= 0;i
< BDF_FONT_CLEAR_SIZE
;i
++)
424 HeapFree(hbdf_bmp_heap
, 0, p
->pbmp
);
425 p
->psrc
->pcbmp
= NULL
;
429 if (FONT_CACHE_SLOT_OVER_P(p
))
430 p
= cached_bitmap_slots
;
434 #define GET_HEX_VAL(x) ((isdigit(x)) ? ((x) - '0') : \
435 (((x) >= 'A') && ((x) <= 'F')) ? ((x) - 'A' + 10) : \
436 (((x) >= 'a') && ((x) <= 'f')) ? ((x) - 'a' + 10) : \
440 w32_get_bdf_glyph(bdffont
*fontp
, int index
, int size
, glyph_struct
*glyph
)
443 unsigned char *start
, *p
, *q
, *bitmapp
;
444 unsigned char val
, val1
, val2
;
445 int i
, j
, len
, flag
, consumed
;
448 pch
= get_cached_font_char(fontp
, index
);
451 pch
= seek_char(fontp
, index
);
458 if ((size
== 0) && pch
->pcbmp
)
460 glyph
->metric
= pch
->pcbmp
->metric
;
464 len
= fontp
->size
- (start
- fontp
->font
);
466 flag
= proceed_file_line("DWIDTH", start
, &len
, (char **)&p
, (char **)&q
);
469 glyph
->metric
.dwidth
= atoi(p
);
472 flag
= proceed_file_line("BBX", start
, &len
, (char **)&p
, (char **)&q
);
475 glyph
->metric
.bbw
= strtol(p
, (char **)&start
, 10);
477 glyph
->metric
.bbh
= strtol(p
, (char **)&start
, 10);
479 glyph
->metric
.bbox
= strtol(p
, (char **)&start
, 10);
481 glyph
->metric
.bboy
= strtol(p
, (char **)&start
, 10);
483 if (size
== 0) return 1;
486 flag
= proceed_file_line("BITMAP", start
, &len
, (char **)&p
, (char **)&q
);
493 bitmapp
= glyph
->bitmap
;
494 rowbytes
= (glyph
->metric
.bbw
+ 7) / 8;
495 /* DIB requires DWORD alignment. */
496 align
= sizeof(DWORD
) - rowbytes
% sizeof(DWORD
);
497 consumed
= glyph
->metric
.bbh
* (rowbytes
+ align
);
498 glyph
->bitmap_size
= consumed
;
499 glyph
->row_byte_size
= rowbytes
;
500 if (size
< consumed
) return 0;
502 for(i
= 0;i
< glyph
->metric
.bbh
;i
++)
504 q
= memchr(p
, '\n', len
);
506 for(j
= 0;((q
> p
) && (j
< rowbytes
));j
++)
508 int ival
= GET_HEX_VAL(*p
);
510 if (ival
== -1) return 0;
513 ival
= GET_HEX_VAL(*p
);
514 if (ival
== -1) return 0;
517 val
= (unsigned char)((val1
<< 4) | val2
);
521 for(j
= 0;j
< align
;j
++)
526 /* If this glyph is white space, return -1. */
527 if (flag
== 0) return -1;
534 get_bitmap_with_cache(bdffont
*fontp
, int index
)
536 int bitmap_size
, bitmap_real_size
;
542 pch
= get_cached_font_char(fontp
, index
);
549 bitmap_size
= ((fontp
->urx
- fontp
->llx
) / 8 + 3) * (fontp
->ury
- fontp
->lly
)
551 glyph
.bitmap
= (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size
);
553 bitmap_real_size
= w32_get_bdf_glyph(fontp
, index
, bitmap_size
, &glyph
);
555 if (bitmap_real_size
== 0)
558 pch
= get_cached_font_char(fontp
, index
);
559 if (!pch
) return NULL
;
561 if (bitmap_real_size
> 0)
563 pbmp
= (unsigned char*) HeapAlloc(hbdf_bmp_heap
, 0,
565 if (!pbmp
) return NULL
;
566 memcpy(pbmp
, glyph
.bitmap
, bitmap_real_size
);
569 pbmp
= NULL
; /* white space character */
571 pcb
= pcached_bitmap_latest
;
573 clear_cached_bitmap_slots();
576 pcb
->metric
= glyph
.metric
;
578 pcb
->bitmap_size
= glyph
.bitmap_size
;
579 pcb
->row_byte_size
= glyph
.row_byte_size
;
583 pcached_bitmap_latest
++;
584 if (FONT_CACHE_SLOT_OVER_P(pcached_bitmap_latest
))
585 pcached_bitmap_latest
= cached_bitmap_slots
;
591 create_offscreen_bitmap(HDC hdc
, int width
, int height
, unsigned char **bitsp
)
598 memset(&info
, 0, sizeof(info
));
599 info
.h
.biSize
= sizeof(BITMAPINFOHEADER
);
600 info
.h
.biWidth
= width
;
601 info
.h
.biHeight
= -height
;
603 info
.h
.biBitCount
= 1;
604 info
.h
.biCompression
= BI_RGB
;
605 info
.c
[1].rgbRed
= info
.c
[1].rgbGreen
= info
.c
[1].rgbBlue
= 255;
607 return CreateDIBSection(hdc
, (LPBITMAPINFO
)&info
,
608 DIB_RGB_COLORS
, (void **)bitsp
, NULL
, 0);
612 w32_BDF_TextMetric(bdffont
*fontp
, unsigned char *text
, int dim
)
620 index
= MAKELENDSHORT(text
[1], text
[0]);
622 pcb
= get_bitmap_with_cache(fontp
, index
);
626 return &(pcb
->metric
);
630 w32_BDF_TextOut(bdffont
*fontp
, HDC hdc
, int left
,
631 int top
, unsigned char *text
, int dim
, int bytelen
,
632 int fixed_pitch_size
)
635 unsigned char *textp
;
637 HBRUSH hFgBrush
, hOrgBrush
;
643 static HBITMAP hBMP
= 0;
644 static HDC DIBsection_hdc
= 0;
645 static int DIBsection_width
, DIBsection_height
;
646 static unsigned char *bits
;
648 hCompatDC
= CreateCompatibleDC(hdc
);
652 textalign
= GetTextAlign(hdc
);
654 hFgBrush
= CreateSolidBrush(GetTextColor(hdc
));
655 hOrgBrush
= SelectObject(hdc
, hFgBrush
);
669 if (bytelen
< 0) break;
670 index
= MAKELENDSHORT(textp
[0], textp
[1]);
673 pcb
= get_bitmap_with_cache(fontp
, index
);
681 width
= pcb
->metric
.bbw
;
682 height
= pcb
->metric
.bbh
;
685 && (DIBsection_hdc
== hdc
)
686 && (DIBsection_width
== width
)
687 && (DIBsection_height
== height
)))
689 if (hBMP
) DeleteObject(hBMP
);
690 hBMP
= create_offscreen_bitmap(hdc
, width
, height
, &bits
);
691 DIBsection_hdc
= hdc
;
692 DIBsection_width
= width
;
693 DIBsection_height
= height
;
697 memcpy(bits
, pcb
->pbmp
, pcb
->bitmap_size
);
699 if (textalign
& TA_BASELINE
)
700 btop
= top
- (pcb
->metric
.bbh
+ pcb
->metric
.bboy
);
701 else if (textalign
& TA_BOTTOM
)
702 btop
= top
- pcb
->metric
.bbh
;
706 horgobj
= SelectObject(hCompatDC
, hBMP
);
707 BitBlt(hdc
, left
, btop
, width
, height
, hCompatDC
, 0, 0, 0xE20746);
708 SelectObject(hCompatDC
, horgobj
);
711 if (fixed_pitch_size
)
712 left
+= fixed_pitch_size
;
714 left
+= pcb
->metric
.dwidth
;
719 SelectObject(hdc
, hOrgBrush
);
720 DeleteObject(hFgBrush
);
725 struct font_info
*w32_load_bdf_font (struct frame
*f
, char *fontname
,
726 int size
, char* filename
)
728 struct w32_display_info
*dpyinfo
= FRAME_W32_DISPLAY_INFO (f
);
729 struct font_info
*fontp
;
733 bdf_font
= w32_init_bdf_font (filename
);
735 if (!bdf_font
) return NULL
;
737 font
= (XFontStruct
*) xmalloc (sizeof (XFontStruct
));
738 bzero (font
, sizeof (*font
));
740 font
->bdf
= bdf_font
;
743 /* NTEMACS_TODO: Better way of determining if a font is double byte
745 font
->double_byte_p
= bdf_font
->nchars
> 255 ? 1 : 0;
747 w32_cache_char_metrics (font
);
749 /* Do we need to create the table? */
750 if (dpyinfo
->font_table_size
== 0)
752 dpyinfo
->font_table_size
= 16;
754 = (struct font_info
*) xmalloc (dpyinfo
->font_table_size
755 * sizeof (struct font_info
));
757 /* Do we need to grow the table? */
758 else if (dpyinfo
->n_fonts
759 >= dpyinfo
->font_table_size
)
761 dpyinfo
->font_table_size
*= 2;
763 = (struct font_info
*) xrealloc (dpyinfo
->font_table
,
764 (dpyinfo
->font_table_size
765 * sizeof (struct font_info
)));
768 fontp
= dpyinfo
->font_table
+ dpyinfo
->n_fonts
;
770 /* Now fill in the slots of *FONTP. */
772 bzero (fontp
, sizeof (*fontp
));
774 fontp
->font_idx
= dpyinfo
->n_fonts
;
775 fontp
->name
= (char *) xmalloc (strlen (fontname
) + 1);
776 bcopy (fontname
, fontp
->name
, strlen (fontname
) + 1);
777 fontp
->full_name
= fontp
->name
;
778 /* FIXME: look at BDF spec to see if there are better ways of finding
779 average_width and space_width, hopefully that don't involve working out
780 the values for ourselves from the data. */
781 fontp
->size
= fontp
->average_width
= fontp
->space_width
= FONT_WIDTH (font
);
782 fontp
->height
= FONT_HEIGHT (font
);
784 /* The slot `encoding' specifies how to map a character
785 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
786 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF, 0:0x2020..0x7F7F,
787 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
788 0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
789 2:0xA020..0xFF7F). For the moment, we don't know which charset
790 uses this font. So, we set informatoin in fontp->encoding[1]
791 which is never used by any charset. If mapping can't be
792 decided, set FONT_ENCODING_NOT_DECIDED. */
793 fontp
->encoding
[1] = FONT_ENCODING_NOT_DECIDED
;
794 fontp
->baseline_offset
= bdf_font
->yoffset
;
795 fontp
->relative_compose
= bdf_font
->relative_compose
;
796 fontp
->default_ascent
= bdf_font
->default_ascent
;
798 /* Set global flag fonts_changed_p to non-zero if the font loaded
799 has a character with a smaller width than any other character
800 before, or if the font loaded has a smaller height than any
801 other font loaded before. If this happens, it will make a
802 glyph matrix reallocation necessary. */
803 fonts_changed_p
|= x_compute_min_glyph_bounds (f
);
810 /* Check a file for an XLFD string describing it. */
811 int w32_BDF_to_x_font (char *file
, char* xstr
, int len
)
813 HANDLE hfile
, hfilemap
;
814 BY_HANDLE_FILE_INFORMATION fileinfo
;
815 char *font
, *start
, *p
, *q
;
816 int flag
, size
, retval
= 0;
818 hfile
= CreateFile (file
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
819 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
820 if (hfile
== INVALID_HANDLE_VALUE
) return 0;
821 if (!GetFileInformationByHandle(hfile
, &fileinfo
) ||
822 (fileinfo
.nFileSizeHigh
!= 0) ||
823 (fileinfo
.nFileSizeLow
> BDF_FILE_SIZE_MAX
))
828 size
= fileinfo
.nFileSizeLow
;
830 hfilemap
= CreateFileMapping (hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
837 font
= MapViewOfFile (hfilemap
, FILE_MAP_READ
, 0, 0, 0);
841 CloseHandle (hfilemap
);
846 flag
= proceed_file_line ("FONT ", start
, &size
, &p
, &q
);
849 /* If font provides a description of itself, check it is a
850 full XLFD before accepting it. */
854 for (s
= p
; s
< q
; s
++)
859 if (count
== 14 && q
- p
- 1 <= len
)
861 strncpy (xstr
, p
, q
-p
-1);
863 /* Files may have DOS line ends (ie still ^M on end). */
864 if (iscntrl(xstr
[q
-p
-2]))
870 UnmapViewOfFile (font
);
872 CloseHandle (hfilemap
);
876 /* arch-tag: 2e9a45de-0c54-4a0e-95c8-2d67b2b1fa32
877 (do not change this comment) */