Basic FreeType renderer implementation.
[gdipp.git] / gdipp_server / font_proxy.cpp
bloba8c76fd5f8f1daad526cc877b334fb81cfcc3963
1 #include "stdafx.h"
2 #include "font_man.h"
3 #include "freetype.h"
5 #define TTCF_TABLE_TAG mmioFOURCC('t', 't', 'c', 'f')
7 // little-endian <-> big-endian
8 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
9 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
11 DWORD font_holder_tls_index = 0;
13 unsigned long gdimm_font_man::stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
15 // callback function, called when freetype requests font data
17 error_status_t rpc_error;
19 // count == 0 means seek operation
20 if (count == 0)
21 return 0;
23 const long font_id = stream->descriptor.value;
25 const font_info *info = font_man_instance.get_font_info(font_id);
26 assert(info != NULL);
28 DWORD read_size;
29 if (font_id < 0)
31 HDC font_holder = reinterpret_cast<HDC>(TlsGetValue(font_holder_tls_index));
32 assert(font_holder != NULL);
33 read_size = GetFontData(font_holder, info->table_header, offset, buffer, count);
35 else
37 rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, info->table_header, offset, buffer, count, &read_size);
38 assert(rpc_error == 0);
40 assert(read_size == count);
42 return read_size;
45 int gdimm_font_man::lookup_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph)
47 FT_Error ft_error;
49 FT_Size size;
50 ft_error = FTC_Manager_LookupSize(ft_cache_man, scaler, &size);
51 assert(ft_error == 0);
53 FT_Vector delta;
54 ft_error = FT_Get_Kerning(size->face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &delta);
55 assert(ft_error == 0);
57 return int_from_26dot6(delta.x);
60 void gdimm_font_man::stream_close(FT_Stream stream)
62 // GetFontData() needs no close
65 gdimm_font_man::gdimm_font_man()
67 font_holder_tls_index = TlsAlloc();
68 assert(font_holder_tls_index != TLS_OUT_OF_INDEXES);
71 gdimm_font_man::~gdimm_font_man()
73 BOOL b_ret;
75 b_ret = TlsFree(font_holder_tls_index);
76 assert(b_ret);
79 const font_info * gdimm_font_man::get_font_info(long font_id)
81 return &_id_to_info[font_id];
84 FT_Stream gdimm_font_man::lookup_stream(long font_id)
86 return &_id_to_info[font_id].stream;
89 ULONG gdimm_font_man::lookup_face_index(long font_id)
91 return _id_to_info[font_id].face_index;
94 const os2_metrics *gdimm_font_man::lookup_os2_metrics(long font_id)
96 return &_id_to_info[font_id].os2_metrics;
99 long gdimm_font_man::register_font(HDC font_holder, const wchar_t *font_face)
101 TlsSetValue(font_holder_tls_index, font_holder);
103 std::map<std::wstring, long>::const_iterator iter = _name_to_id.find(font_face);
104 if (iter == _name_to_id.end())
106 // double-check lock
107 gdimm_lock lock(LOCK_REG_FONT);
108 iter = _name_to_id.find(font_face);
109 if (iter == _name_to_id.end())
111 long new_font_id;
112 if (_id_to_info.empty())
113 new_font_id = -1;
114 else
115 new_font_id = (long) _id_to_info.begin()->first - 1;
117 font_info new_font_data = {};
118 new_font_data.stream.size = get_font_size(font_holder, new_font_data.table_header);
119 new_font_data.stream.descriptor.value = new_font_id;
120 new_font_data.stream.read = gdimm_font_man::stream_io;
121 new_font_data.stream.close = gdimm_font_man::stream_close;
123 if (new_font_data.table_header != 0)
125 new_font_data.face_index = get_ttc_face_index(font_holder, new_font_data.stream.size);
126 assert(new_font_data.face_index != ULONG_MAX);
129 new_font_data.os2_metrics.init(font_holder);
131 _name_to_id[font_face] = new_font_id;
132 _id_to_info[new_font_id] = new_font_data;
134 return new_font_id;
138 return iter->second;
141 long gdimm_font_man::link_font(const LOGFONTW &linked_font_attr, std::wstring &linked_font_face)
143 error_status_t rpc_error;
144 long font_id;
146 rpc_error = gdipp_rpc_register_font(h_gdipp_rpc, reinterpret_cast<const byte *>(&linked_font_attr), sizeof(linked_font_attr), reinterpret_cast<unsigned long *>(&font_id));
147 assert(rpc_error == 0 && font_id >= 0);
149 std::map<long, font_info>::const_iterator iter = _id_to_info.find(font_id);
150 if (iter == _id_to_info.end())
152 // double-check lock
153 gdimm_lock lock(LOCK_REG_FONT);
154 iter = _id_to_info.find(font_id);
155 if (iter == _id_to_info.end())
157 font_info new_font_data = {};
158 new_font_data.stream.size = get_font_size(font_id, new_font_data.table_header);
159 new_font_data.stream.descriptor.value = font_id;
160 new_font_data.stream.read = gdimm_font_man::stream_io;
161 new_font_data.stream.close = gdimm_font_man::stream_close;
163 if (new_font_data.table_header != 0)
165 new_font_data.face_index = get_ttc_face_index(font_id, new_font_data.stream.size);
166 assert(new_font_data.face_index != ULONG_MAX);
169 new_font_data.os2_metrics.init(font_id);
171 _id_to_info[font_id] = new_font_data;
175 DWORD metric_buf_size;
177 rpc_error = gdipp_rpc_get_font_metrics_size(h_gdipp_rpc, font_id, &metric_buf_size);
178 assert(rpc_error == 0 && metric_buf_size > 0);
180 byte *font_metrics = new byte[metric_buf_size];
182 rpc_error = gdipp_rpc_get_font_metrics_data(h_gdipp_rpc, font_id, font_metrics, metric_buf_size, &metric_buf_size);
183 assert(rpc_error == 0 && metric_buf_size > 0);
185 linked_font_face = metric_face_name(font_metrics);
187 delete[] font_metrics;
189 return font_id;
192 void gdimm_font_man::get_glyph_indices(long font_id, const wchar_t *str, int count, wchar_t *gi)
194 error_status_t rpc_error;
195 DWORD converted;
197 if (font_id < 0)
199 HDC font_holder = reinterpret_cast<HDC>(TlsGetValue(font_holder_tls_index));
200 assert(font_holder != NULL);
201 converted = GetGlyphIndices(font_holder, str, count, reinterpret_cast<LPWORD>(gi), GGI_MARK_NONEXISTING_GLYPHS);
203 else
205 rpc_error = gdipp_rpc_get_glyph_indices(h_gdipp_rpc, font_id, str, count, reinterpret_cast<unsigned short *>(gi), &converted);
206 assert(rpc_error == 0);
208 assert(converted == count);
211 DWORD gdimm_font_man::get_font_size(HDC font_holder, DWORD &table_header)
213 table_header = TTCF_TABLE_TAG;
216 try to get font file size with ttcf tag first
217 if succeeds, the font face is part of a TTC file
218 otherwise, the font face is a standalone TrueType font file
220 DWORD font_size = GetFontData(font_holder, table_header, 0, NULL, 0);
221 if (font_size == GDI_ERROR)
223 table_header = 0;
224 font_size = GetFontData(font_holder, table_header, 0, NULL, 0);
225 assert(font_size != GDI_ERROR);
228 return font_size;
231 DWORD gdimm_font_man::get_font_size(long font_id, DWORD &table_header)
233 error_status_t rpc_error;
234 table_header = TTCF_TABLE_TAG;
235 DWORD font_size;
238 try to get font file size with ttcf tag first
239 if succeeds, the font face is part of a TTC file
240 otherwise, the font face is a standalone TrueType font file
242 rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, table_header, 0, &font_size);
243 if (rpc_error != 0)
244 return 0;
246 if (font_size == GDI_ERROR)
248 table_header = 0;
249 rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, table_header, 0, &font_size);
250 assert(rpc_error == 0 && font_size != GDI_ERROR);
253 return font_size;
256 ULONG gdimm_font_man::get_ttc_face_index(HDC font_holder, DWORD ttc_file_size)
258 // get the index of the current face in its TTC file
259 // by comparing its start offset retrieved from GetFontData and from the TTC header
261 // pre-condition: the font file contains TTC header
263 DWORD read_size;
265 // start offset of the current face
266 DWORD face_start = GetFontData(font_holder, 0, 0, NULL, 0);
267 assert(face_start != GDI_ERROR);
268 face_start = ttc_file_size - face_start;
270 DWORD read_offset = sizeof(DWORD) + sizeof(FIXED);
271 ULONG face_count;
272 DWORD buffer_len = sizeof(face_count);
274 // number of face records in the TTC header
275 read_size = GetFontData(font_holder, TTCF_TABLE_TAG, read_offset, &face_count, buffer_len);
276 assert(read_size == buffer_len);
278 // TrueType font data uses big-endian, while mainstream Windows uses little-endian platforms
279 face_count = SWAPLONG(face_count);
280 read_offset += buffer_len;
282 for (ULONG i = 0; i < face_count; ++i)
284 // start offset of the current record
285 DWORD curr_start;
286 buffer_len = sizeof(curr_start);
287 read_size = GetFontData(font_holder, TTCF_TABLE_TAG, read_offset, &curr_start, buffer_len);
288 assert(read_size == buffer_len);
289 curr_start = SWAPLONG(curr_start);
291 if (curr_start == face_start)
292 return i;
294 read_offset += buffer_len;
297 return ULONG_MAX;
300 ULONG gdimm_font_man::get_ttc_face_index(long font_id, DWORD ttc_file_size)
302 // get the index of the current face in its TTC file
303 // by comparing its start offset retrieved from GetFontData and from the TTC header
305 // pre-condition: the font file contains TTC header
307 error_status_t rpc_error;
308 DWORD face_start, read_size;
310 // start offset of the current face
311 rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, 0, 0, &face_start);
312 assert(rpc_error == 0 && face_start != GDI_ERROR);
313 face_start = ttc_file_size - face_start;
315 DWORD read_offset = sizeof(DWORD) + sizeof(FIXED);
316 ULONG face_count;
317 DWORD buffer_len = sizeof(face_count);
319 // number of face records in the TTC header
320 rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, TTCF_TABLE_TAG, read_offset, reinterpret_cast<byte *>(&face_count), buffer_len, &read_size);
321 assert(rpc_error == 0 && read_size == buffer_len);
323 // TrueType font data uses big-endian, while mainstream Windows uses little-endian platforms
324 face_count = SWAPLONG(face_count);
325 read_offset += buffer_len;
327 for (ULONG i = 0; i < face_count; ++i)
329 // start offset of the current record
330 DWORD curr_start;
331 buffer_len = sizeof(curr_start);
332 rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, TTCF_TABLE_TAG, read_offset, reinterpret_cast<byte *>(&curr_start), buffer_len, &read_size);
333 assert(rpc_error == 0 && read_size == buffer_len);
334 curr_start = SWAPLONG(curr_start);
336 if (curr_start == face_start)
337 return i;
339 read_offset += buffer_len;
342 return ULONG_MAX;