Basic FreeType renderer implementation.
[gdipp.git] / gdipp_server / font_mgr.cpp
bloba9faac76fbaa439c1444d5035cb6cbd6b4e9a91d
1 #include "stdafx.h"
2 #include "font_mgr.h"
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)))
14 namespace gdipp
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)
29 *table_header = 0;
30 font_size = GetFontData(font_holder, *table_header, 0, NULL, 0);
31 assert(font_size != GDI_ERROR);
34 return font_size;
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
44 DWORD read_size;
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);
52 ULONG face_count;
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
66 DWORD curr_start;
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)
73 return i;
75 read_offset += buffer_len;
78 return ULONG_MAX;
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
85 bool b_ret;
86 font_entry *font_id = NULL;
87 HDC font_holder;
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);
96 if (hfont == NULL)
97 return NULL;
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
104 if (hdc == NULL)
106 font_holder = dc_pool_instance.claim();
107 assert(font_holder != NULL);
109 else
111 font_holder = hdc;
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())
128 os2_metrics os2;
129 b_ret = os2.init(font_holder);
130 if (!b_ret)
131 goto clean_up_and_return;
133 DWORD table_header;
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;
151 font_id->os2 = os2;
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;
160 delete_font = false;
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;
170 clean_up_and_return:
171 // if anything failed, delete created font
172 if (delete_font)
173 DeleteObject(hfont);
175 if (hdc == NULL)
176 dc_pool_instance.free(font_holder);
178 return font_id;
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);
196 HDC font_holder;
198 if (hdc == NULL)
200 font_holder = dc_pool_instance.claim();
201 assert(font_holder != NULL);
203 else
205 font_holder = hdc;
207 SelectObject(font_holder, curr_font->font_handle);
209 const DWORD data_size = GetFontData(font_holder, table, offset, data_buf, buf_size);
211 if (hdc == NULL)
212 dc_pool_instance.free(font_holder);
214 return data_size;
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);
220 HDC font_holder;
222 if (hdc == NULL)
224 font_holder = dc_pool_instance.claim();
225 assert(font_holder != NULL);
227 else
229 font_holder = hdc;
231 SelectObject(font_holder, curr_font->font_handle);
233 const DWORD converted = GetGlyphIndices(font_holder, str, count, gi, GGI_MARK_NONEXISTING_GLYPHS);
235 if (hdc == NULL)
236 dc_pool_instance.free(font_holder);
238 return converted;
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
273 if (count == 0)
274 return 0;
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);
280 return read_size;
283 void font_mgr::stream_close(FT_Stream stream)
285 // GetFontData() needs no close