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 "blockinput.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
);
47 search_file_line(char *key
, char *start
, int len
, char **val
, char **next
)
52 p
= memchr(start
, '\n', len
);
54 for (;start
< p
;start
++)
56 if ((*start
!= ' ') || (*start
!= '\t')) break;
58 linelen
= p
- start
+ 1;
60 if (strncmp(start
, key
, min(strlen(key
), linelen
)) == 0)
62 *val
= start
+ strlen(key
);
70 proceed_file_line(char *key
, char *start
, int *len
, char **val
, char **next
)
75 flag
= search_file_line(key
, start
, *len
, val
, next
);
76 *len
-= (int)(*next
- start
);
80 if (flag
== -1) return 0;
85 get_quoted_string(char *start
, char *end
)
89 p
= memchr(start
, '\"', end
- start
);
94 q
= memchr(p
, '\"', end
- q
);
97 result
= (char*) xmalloc(q
- p
+ 1);
99 memcpy(result
, p
, q
- p
);
100 result
[q
- p
] = '\0';
106 set_bdf_font_info(bdffont
*fontp
)
108 unsigned char *start
, *p
, *q
;
110 int bbw
, bbh
, bbx
, bby
;
117 fontp
->relative_compose
= 0;
118 fontp
->default_ascent
= 0;
119 fontp
->registry
= NULL
;
120 fontp
->encoding
= NULL
;
122 /* fontp->width = NULL; */
124 flag
= proceed_file_line("FONTBOUNDINGBOX", start
, &len
, &p
, &q
);
126 bbw
= strtol(p
, &start
, 10);
128 bbh
= strtol(p
, &start
, 10);
130 bbx
= strtol(p
, &start
, 10);
132 bby
= strtol(p
, &start
, 10);
136 fontp
->urx
= bbw
+ bbx
;
137 fontp
->ury
= bbh
+ bby
;
141 flag
= proceed_file_line("STARTPROPERTIES", start
, &len
, &p
, &q
);
148 if (search_file_line("PIXEL_SIZE", start
, len
, &p
, &q
) == 1)
153 else if (search_file_line("FONT_ASCENT", start
, len
, &p
, &q
) == 1)
158 else if (search_file_line("FONT_DESCENT", start
, len
, &p
, &q
) == 1)
163 else if (search_file_line("_MULE_BASELINE_OFFSET", start
, len
, &p
, &q
) == 1)
166 fontp
->yoffset
= val1
;
168 else if (search_file_line("_MULE_RELATIVE_COMPOSE", start
, len
, &p
, &q
) == 1)
171 fontp
->relative_compose
= val1
;
173 else if (search_file_line("_MULE_DEFAULT_ASCENT", start
, len
, &p
, &q
) == 1)
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);
198 flag
= search_file_line("ENDPROPERTIES", start
, len
, &p
, &q
);
200 if (flag
== -1) return 0;
204 flag
= proceed_file_line("CHARS", start
, &len
, &p
, &q
);
212 w32_init_bdf_font(char *filename
)
214 HANDLE hfile
, hfilemap
;
217 BY_HANDLE_FILE_INFORMATION fileinfo
;
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
))
228 error("Fail to open BDF file.");
230 hfilemap
= CreateFileMapping(hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
231 if (hfilemap
== INVALID_HANDLE_VALUE
)
234 error("Can't map font.");
237 font
= MapViewOfFile(hfilemap
, FILE_MAP_READ
, 0, 0, 0);
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!");
266 w32_free_bdf_font(bdffont
*fontp
)
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
];
287 for (j
= 0;j
< BDF_SECOND_OFFSET_TABLE
;j
++)
290 if (pcb
) pcb
->psrc
= NULL
;
299 get_cached_font_char(bdffont
*fontp
, int index
)
301 font_char
*pch
, *result
;
307 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
310 result
= &pch
[BDF_SECOND_OFFSET(index
)];
312 if (!result
->offset
) return NULL
;
318 cache_char_offset(bdffont
*fontp
, int index
, unsigned char *offset
)
320 font_char
*pch
, *result
;
326 pch
= fontp
->chtbl
[BDF_FIRST_OFFSET(index
)];
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
;
342 seek_char(bdffont
*fontp
, int index
)
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
);
354 flag
= proceed_file_line("ENCODING", start
, &len
, &p
, &q
);
357 fontp
->seeked
= 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
;
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) : \
377 w32_get_bdf_glyph(bdffont
*fontp
, int index
, int size
, glyph_struct
*glyph
)
380 unsigned char *start
, *p
, *q
, *bitmapp
;
381 unsigned char val1
, val2
;
384 pch
= get_cached_font_char(fontp
, index
);
387 pch
= seek_char(fontp
, index
);
394 if ((size
== 0) && pch
->pcbmp
)
396 glyph
->metric
= pch
->pcbmp
->metric
;
400 len
= fontp
->size
- (start
- fontp
->font
);
402 flag
= proceed_file_line("DWIDTH", start
, &len
, &p
, &q
);
405 glyph
->metric
.dwidth
= atoi(p
);
408 flag
= proceed_file_line("BBX", start
, &len
, &p
, &q
);
411 glyph
->metric
.bbw
= strtol(p
, &start
, 10);
413 glyph
->metric
.bbh
= strtol(p
, &start
, 10);
415 glyph
->metric
.bbox
= strtol(p
, &start
, 10);
417 glyph
->metric
.bboy
= strtol(p
, &start
, 10);
419 if (size
== 0) return 1;
422 flag
= proceed_file_line("BITMAP", start
, &len
, &p
, &q
);
427 bitmapp
= glyph
->bitmap
;
428 for(i
= 0;i
< glyph
->metric
.bbh
;i
++)
430 q
= memchr(p
, '\n', len
);
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;
437 val2
= GET_HEX_VAL(*p
);
438 if (val2
== -1) return 0;
441 if (size
<= 0) return 0;
442 /* NAND Operation. */
443 *bitmapp
++ = (unsigned char)~((val1
<< 4) | val2
);
445 /* CreateBitmap requires WORD alignment. */
456 #define NEXT_CACHE_SLOT(n) (((n) + 1 >= BDF_FONT_CACHE_SIZE) ? 0 : ((n) + 1))
460 get_bitmap_with_cache(bdffont
*fontp
, int index
)
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
);
480 bitmap_size
= ((fontp
->urx
- fontp
->llx
) / 8 + 2) * (fontp
->ury
- fontp
->lly
)
482 glyph
.bitmap
= (unsigned char*) alloca(sizeof(unsigned char) * bitmap_size
);
484 if (!w32_get_bdf_glyph(fontp
, index
, bitmap_size
, &glyph
))
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. */
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
];
508 DeleteObject(p
->hbmp
);
509 p
->psrc
->pcbmp
= NULL
;
517 hbmp
= CreateBitmap (glyph
.metric
.bbw
, glyph
.metric
.bbh
,
520 pcb
= &cached_bitmap_slots
[cache_in_slot
];
523 pcb
->metric
= glyph
.metric
;
528 cache_in_slot
= NEXT_CACHE_SLOT(cache_in_slot
);
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
)
540 unsigned char *textp
;
544 HBRUSH hFgBrush
, hOrgBrush
;
549 hCompatDC
= CreateCompatibleDC(hdc
);
551 textalign
= GetTextAlign(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));
571 if (bytelen
< 0) break;
572 index
= MAKELENDSHORT(textp
[1], textp
[0]);
575 pcb
= get_bitmap_with_cache(fontp
, index
);
580 SelectObject(hCompatDC
, horgobj
);
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
;
596 SelectObject(hCompatDC
, hBMP
);
598 horgobj
= SelectObject(hCompatDC
, hBMP
);
600 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, SRCCOPY
);
602 BitBlt(hdc
, left
, btop
, pcb
->metric
.bbw
, pcb
->metric
.bbh
, hCompatDC
, 0, 0, 0xB8074A);
604 if (fixed_pitch_size
)
605 left
+= fixed_pitch_size
;
607 left
+= pcb
->metric
.dwidth
;
609 SelectObject(hCompatDC
, horgobj
);
610 SelectObject(hdc
, hOrgBrush
);
611 DeleteObject(hFgBrush
);
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
;
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
;
635 /* Do we need to create the table? */
636 if (dpyinfo
->font_table_size
== 0)
638 dpyinfo
->font_table_size
= 16;
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;
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. */
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
;
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
))
703 size
= fileinfo
.nFileSizeLow
;
705 hfilemap
= CreateFileMapping (hfile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
706 if (hfilemap
== INVALID_HANDLE_VALUE
)
712 font
= MapViewOfFile (hfilemap
, FILE_MAP_READ
, 0, 0, 0);
716 CloseHandle (hfilemap
);
721 flag
= proceed_file_line ("FONT ", start
, &size
, &p
, &q
);
724 /* If font provides a description of itself, check it is a
725 full XLFD before accepting it. */
729 for (s
= p
; s
< q
; s
++)
734 if (count
== 14 && q
- p
- 1 <= len
)
736 strncpy (xstr
, p
, q
-p
-1);
738 /* Files may have DOS line ends (ie still ^M on end). */
739 if (iscntrl(xstr
[q
-p
-2]))
746 CloseHandle (hfilemap
);