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
)
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
;
351 if (!fontp
->seeked
) return NULL
;
353 start
= fontp
->seeked
;
354 len
= fontp
->size
- (start
- fontp
->font
);
357 flag
= proceed_file_line("ENCODING", start
, &len
, &p
, &q
);
360 fontp
->seeked
= 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
;
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) : \
380 w32_get_bdf_glyph(bdffont
*fontp
, int index
, int size
, glyph_struct
*glyph
)
383 unsigned char *start
, *bitmapp
;
388 pch
= get_cached_font_char(fontp
, index
);
391 pch
= seek_char(fontp
, index
);
398 if ((size
== 0) && pch
->pcbmp
)
400 glyph
->metric
= pch
->pcbmp
->metric
;
404 len
= fontp
->size
- (start
- fontp
->font
);
406 flag
= proceed_file_line("DWIDTH", start
, &len
, &p
, &q
);
409 glyph
->metric
.dwidth
= atoi(p
);
412 flag
= proceed_file_line("BBX", start
, &len
, &p
, &q
);
415 glyph
->metric
.bbw
= strtol(p
, &start
, 10);
417 glyph
->metric
.bbh
= strtol(p
, &start
, 10);
419 glyph
->metric
.bbox
= strtol(p
, &start
, 10);
421 glyph
->metric
.bboy
= strtol(p
, &start
, 10);
423 if (size
== 0) return 1;
426 flag
= proceed_file_line("BITMAP", start
, &len
, &p
, &q
);
431 bitmapp
= glyph
->bitmap
;
432 for(i
= 0;i
< glyph
->metric
.bbh
;i
++)
434 q
= memchr(p
, '\n', len
);
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;
441 val2
= GET_HEX_VAL(*p
);
442 if (val2
== -1) return 0;
445 if (size
<= 0) return 0;
446 /* NAND Operation. */
447 *bitmapp
++ = (unsigned char)~((val1
<< 4) | val2
);
449 /* CreateBitmap requires WORD alignment. */
460 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
464 get_bitmap_with_cache(bdffont
*fontp
, int index
)
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
);
484 bitmap_size
= ((fontp
->urx
- fontp
->llx
) / 8 + 2) * (fontp
->ury
- fontp
->lly
)
486 glyph
.bitmap
= (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size
);
488 if (!w32_get_bdf_glyph(fontp
, index
, bitmap_size
, &glyph
))
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. */
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
];
512 DeleteObject(p
->hbmp
);
513 p
->psrc
->pcbmp
= NULL
;
521 hbmp
= CreateBitmap (glyph
.metric
.bbw
, glyph
.metric
.bbh
,
524 pcb
= &cached_bitmap_slots
[cache_in_slot
];
527 pcb
->metric
= glyph
.metric
;
532 cache_in_slot
= NEXT_CACHE_SLOT(cache_in_slot
);
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
)
544 unsigned char *textp
;
548 HBRUSH hFgBrush
, hOrgBrush
;
553 hCompatDC
= CreateCompatibleDC(hdc
);
555 textalign
= GetTextAlign(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));
575 if (bytelen
< 0) break;
576 index
= MAKELENDSHORT(textp
[1], textp
[0]);
579 pcb
= get_bitmap_with_cache(fontp
, index
);
584 SelectObject(hCompatDC
, horgobj
);
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
;
600 SelectObject(hCompatDC
, hBMP
);
602 horgobj
= SelectObject(hCompatDC
, hBMP
);
604 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, SRCCOPY
);
606 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, 0xB8074A);
608 if (fixed_pitch_size
)
609 left
+= fixed_pitch_size
;
611 left
+= pcb
->metric
.dwidth
;
613 SelectObject(hCompatDC
, horgobj
);
614 SelectObject(hdc
, hOrgBrush
);
615 DeleteObject(hFgBrush
);
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
;
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
;
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;
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;
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. */
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
;
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
))
710 size
= fileinfo
.nFileSizeLow
;
712 hfilemap
= CreateFileMapping (hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
713 if (hfilemap
== INVALID_HANDLE_VALUE
)
719 font
= MapViewOfFile (hfilemap
, FILE_MAP_READ
, 0, 0, 0);
723 CloseHandle (hfilemap
);
728 flag
= proceed_file_line ("FONT ", start
, &size
, &p
, &q
);
731 /* If font provides a description of itself, check it is a
732 full XLFD before accepting it. */
736 for (s
= p
; s
< q
; s
++)
741 if (count
== 14 && q
- p
- 1 <= len
)
743 strncpy (xstr
, p
, q
-p
-1);
745 /* Files may have DOS line ends (ie still ^M on end). */
746 if (iscntrl(xstr
[q
-p
-2]))
753 CloseHandle (hfilemap
);