3 #include "gdipp_lib/lock.h"
4 #include "gdipp_server/freetype.h"
5 #include "gdipp_server/global.h"
6 #include "gdipp_server/helper.h"
8 #define TTCF_TABLE_TAG mmioFOURCC('t', 't', 'c', 'f')
10 // little-endian <-> big-endian
11 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
12 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
17 DWORD
font_mgr::get_font_size(HDC font_holder
, DWORD
*table_header
)
19 *table_header
= TTCF_TABLE_TAG
;
22 try to get font file size with ttcf tag first
23 if succeeds, the font face is part of a TTC file
24 otherwise, the font face is a standalone TrueType font file
26 DWORD font_size
= GetFontData(font_holder
, *table_header
, 0, NULL
, 0);
27 if (font_size
== GDI_ERROR
)
30 font_size
= GetFontData(font_holder
, *table_header
, 0, NULL
, 0);
31 assert(font_size
!= GDI_ERROR
);
37 ULONG
font_mgr::get_ttc_face_index(HDC font_holder
, DWORD ttc_file_size
)
39 // get the index of the current face in its TTC file
40 // by comparing its start offset retrieved from GetFontData and from the TTC header
42 // pre-condition: the font file contains TTC header
46 // start offset of the current face
47 DWORD face_start
= GetFontData(font_holder
, 0, 0, NULL
, 0);
48 assert(face_start
!= GDI_ERROR
);
49 face_start
= ttc_file_size
- face_start
;
51 DWORD read_offset
= sizeof(DWORD
) + sizeof(FIXED
);
53 DWORD buffer_len
= sizeof(face_count
);
55 // number of face records in the TTC header
56 read_size
= GetFontData(font_holder
, TTCF_TABLE_TAG
, read_offset
, &face_count
, buffer_len
);
57 assert(read_size
== buffer_len
);
59 // TrueType font data uses big-endian, while mainstream Windows uses little-endian platforms
60 face_count
= SWAPLONG(face_count
);
61 read_offset
+= buffer_len
;
63 for (ULONG i
= 0; i
< face_count
; i
++)
65 // start offset of the current record
67 buffer_len
= sizeof(curr_start
);
68 read_size
= GetFontData(font_holder
, TTCF_TABLE_TAG
, read_offset
, &curr_start
, buffer_len
);
69 assert(read_size
== buffer_len
);
70 curr_start
= SWAPLONG(curr_start
);
72 if (curr_start
== face_start
)
75 read_offset
+= buffer_len
;
81 void *font_mgr::register_font(const LOGFONTW
*log_font
, BYTE
**outline_metrics_buf
, unsigned long *outline_metrics_size
, HDC hdc
)
83 // create a font with supplied LOGFONT and retrieve related information
86 font_entry
*font_id
= NULL
;
89 std::wstring font_face
;
90 std::map
<std::wstring
, font_entry
>::iterator font_iter
;
92 // whether delete the created font when exiting (when anything failed or font existed)
93 bool delete_font
= true;
95 const HFONT hfont
= CreateFontIndirectW(log_font
);
100 if an HDC is supplied, use the HDC to select font
101 otherwise, claim a temporary HDC from DC pool and use it
102 temporary HDC will be freed before exiting function
106 font_holder
= dc_pool_instance
.claim();
107 assert(font_holder
!= NULL
);
112 SelectObject(font_holder
, hfont
);
115 *outline_metrics_size
= get_dc_outline_metrics(font_holder
, outline_metrics_buf
);
116 if (*outline_metrics_size
== 0)
117 goto clean_up_and_return
;
119 const OUTLINETEXTMETRICW
*outline_metrics
= reinterpret_cast<const OUTLINETEXTMETRICW
*>(*outline_metrics_buf
);
120 font_face
= metric_face_name(outline_metrics
);
121 font_iter
= _font_registry
.find(font_face
);
122 if (font_iter
== _font_registry
.end())
124 lock
l(lock::SERVER_FONT_MGR
);
125 font_iter
= _font_registry
.find(font_face
);
126 if (font_iter
== _font_registry
.end())
129 b_ret
= os2
.init(font_holder
);
131 goto clean_up_and_return
;
134 DWORD font_size
= get_font_size(font_holder
, &table_header
);
135 if (font_size
== GDI_ERROR
)
136 goto clean_up_and_return
;
138 DWORD face_index
= 0;
139 if (table_header
!= 0)
141 face_index
= get_ttc_face_index(font_holder
, font_size
);
142 if (face_index
== ULONG_MAX
)
143 goto clean_up_and_return
;
146 const font_entry new_font_data
= {};
147 _font_registry
[font_face
] = new_font_data
;
148 font_id
= &_font_registry
[font_face
];
150 font_id
->font_handle
= hfont
;
152 font_id
->face_index
= face_index
;
153 font_id
->table_header
= table_header
;
155 font_id
->stream
.size
= font_size
;
156 font_id
->stream
.descriptor
.pointer
= font_id
;
157 font_id
->stream
.read
= font_mgr::stream_io
;
158 font_id
->stream
.close
= font_mgr::stream_close
;
162 // goto is require for double checking lock
163 // destructor of the lock will be called before jumping
164 goto clean_up_and_return
;
168 font_id
= &font_iter
->second
;
171 // if anything failed, delete created font
176 dc_pool_instance
.free(font_holder
);
181 HFONT
font_mgr::select_font(void *font_id
, HDC hdc
) const
183 const font_entry
*curr_font
= reinterpret_cast<const font_entry
*>(font_id
);
184 return reinterpret_cast<HFONT
>(SelectObject(hdc
, curr_font
->font_handle
));
187 ULONG
font_mgr::lookup_face_index(void *font_id
) const
189 const font_entry
*curr_font
= reinterpret_cast<const font_entry
*>(font_id
);
190 return curr_font
->face_index
;
193 DWORD
font_mgr::lookup_font_data(void *font_id
, DWORD table
, DWORD offset
, LPVOID data_buf
, DWORD buf_size
, HDC hdc
) const
195 const font_entry
*curr_font
= reinterpret_cast<const font_entry
*>(font_id
);
200 font_holder
= dc_pool_instance
.claim();
201 assert(font_holder
!= NULL
);
207 SelectObject(font_holder
, curr_font
->font_handle
);
209 const DWORD data_size
= GetFontData(font_holder
, table
, offset
, data_buf
, buf_size
);
212 dc_pool_instance
.free(font_holder
);
217 DWORD
font_mgr::lookup_glyph_indices(void *font_id
, const wchar_t *str
, int count
, unsigned short *gi
, HDC hdc
) const
219 const font_entry
*curr_font
= reinterpret_cast<const font_entry
*>(font_id
);
224 font_holder
= dc_pool_instance
.claim();
225 assert(font_holder
!= NULL
);
231 SelectObject(font_holder
, curr_font
->font_handle
);
233 const DWORD converted
= GetGlyphIndices(font_holder
, str
, count
, gi
, GGI_MARK_NONEXISTING_GLYPHS
);
236 dc_pool_instance
.free(font_holder
);
241 const os2_metrics
*font_mgr::lookup_os2_metrics(void *font_id
) const
243 const font_entry
*curr_font
= reinterpret_cast<const font_entry
*>(font_id
);
244 return &curr_font
->os2
;
247 FT_Stream
font_mgr::lookup_stream(void *font_id
) const
249 font_entry
*curr_font
= reinterpret_cast<font_entry
*>(font_id
);
250 return &curr_font
->stream
;
253 unsigned long font_mgr::get_dc_outline_metrics(HDC hdc
, BYTE
**outline_metrics_buf
)
255 // get outline metrics of the DC, which also include the text metrics
257 unsigned long outline_metrics_size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
258 if (outline_metrics_size
== 0)
259 return outline_metrics_size
;
261 *outline_metrics_buf
= new BYTE
[outline_metrics_size
];
262 outline_metrics_size
= GetOutlineTextMetricsW(hdc
, outline_metrics_size
, reinterpret_cast<OUTLINETEXTMETRICW
*>(*outline_metrics_buf
));
263 assert(outline_metrics_size
!= 0);
265 return outline_metrics_size
;
268 unsigned long font_mgr::stream_io(FT_Stream stream
, unsigned long offset
, unsigned char *buffer
, unsigned long count
)
270 // callback function, called when freetype requests font data
272 // count == 0 means seek operation
276 font_entry
*font_id
= reinterpret_cast<font_entry
*>(stream
->descriptor
.pointer
);
277 const DWORD read_size
= font_mgr_instance
.lookup_font_data(font_id
, font_id
->table_header
, offset
, buffer
, count
);
278 assert(read_size
== count
);
283 void font_mgr::stream_close(FT_Stream stream
)
285 // GetFontData() needs no close