Use One-Time Initialization for glyph run caching to avoid duplicate glyph run genera...
[gdipp.git] / gdipp_server / font_mgr.cpp
blob0495b80c81e056b69f15ae7acc3625a4d3ccee07
1 #include "stdafx.h"
2 #include "font_mgr.h"
3 #include "gdipp_lib/scoped_rw_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 font_mgr::font_mgr()
83 _font_holder_tls_index = TlsAlloc();
84 assert(_font_holder_tls_index != TLS_OUT_OF_INDEXES);
87 font_mgr::~font_mgr()
89 for (std::map<std::wstring, _font_entry>::const_iterator iter = _font_registry.begin(); iter != _font_registry.end(); ++iter)
90 DeleteObject(iter->second.font_handle);
92 TlsFree(_font_holder_tls_index);
95 void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE **outline_metrics_buf, unsigned long *outline_metrics_size)
97 // create a font with supplied LOGFONT and retrieve related information
99 bool b_ret;
101 const HFONT hfont = CreateFontIndirectW(log_font);
102 if (hfont == NULL)
103 return NULL;
105 SelectObject(font_holder, hfont);
107 *outline_metrics_size = get_dc_outline_metrics(font_holder, outline_metrics_buf);
108 if (*outline_metrics_size == 0)
110 DeleteObject(hfont);
111 return NULL;
114 const OUTLINETEXTMETRICW *outline_metrics = reinterpret_cast<const OUTLINETEXTMETRICW *>(*outline_metrics_buf);
115 const std::wstring font_face = metric_face_name(outline_metrics);
116 std::map<std::wstring, _font_entry>::iterator font_iter = _font_registry.find(font_face);
117 if (font_iter == _font_registry.end())
119 const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FONT_MGR, false);
120 font_iter = _font_registry.find(font_face);
121 if (font_iter == _font_registry.end())
123 os2_metrics os2;
124 b_ret = os2.init(font_holder);
125 if (!b_ret)
127 DeleteObject(hfont);
128 return NULL;
131 DWORD table_header;
132 DWORD font_size = get_font_size(font_holder, &table_header);
133 if (font_size == GDI_ERROR)
135 DeleteObject(hfont);
136 return NULL;
139 DWORD face_index = 0;
140 if (table_header != 0)
142 face_index = get_ttc_face_index(font_holder, font_size);
143 if (face_index == ULONG_MAX)
145 DeleteObject(hfont);
146 return NULL;
150 const std::pair<std::map<std::wstring, _font_entry>::iterator, bool> insert_ret = _font_registry.insert(std::pair<std::wstring, _font_entry>(font_face, _font_entry()));
151 assert(insert_ret.second);
152 font_iter = insert_ret.first;
154 font_iter->second.font_handle = hfont;
155 font_iter->second.os2 = os2;
156 font_iter->second.face_index = face_index;
157 font_iter->second.table_header = table_header;
159 font_iter->second.stream.size = font_size;
160 // need the table header to retrieve font data (see stream_io())
161 font_iter->second.stream.descriptor.value = table_header;
162 font_iter->second.stream.read = font_mgr::stream_io;
163 font_iter->second.stream.close = font_mgr::stream_close;
165 return &font_iter->second;
169 // font has been created before
170 DeleteObject(hfont);
171 return &font_iter->second;
174 HFONT font_mgr::select_font(void *font_id, HDC hdc) const
176 const _font_entry *curr_font = reinterpret_cast<const _font_entry *>(font_id);
177 return reinterpret_cast<HFONT>(SelectObject(hdc, curr_font->font_handle));
180 ULONG font_mgr::lookup_face_index(void *font_id) const
182 const _font_entry *curr_font = reinterpret_cast<const _font_entry *>(font_id);
183 return curr_font->face_index;
186 const os2_metrics *font_mgr::lookup_os2_metrics(void *font_id) const
188 const _font_entry *curr_font = reinterpret_cast<const _font_entry *>(font_id);
189 return &curr_font->os2;
192 FT_Stream font_mgr::lookup_stream(void *font_id) const
194 _font_entry *curr_font = reinterpret_cast<_font_entry *>(font_id);
195 return &curr_font->stream;
198 HDC font_mgr::get_thread_font_holder() const
200 return reinterpret_cast<HDC>(TlsGetValue(_font_holder_tls_index));
203 BOOL font_mgr::set_thread_font_holder(HDC font_holder) const
205 return TlsSetValue(_font_holder_tls_index, font_holder);
208 unsigned long font_mgr::get_dc_outline_metrics(HDC hdc, BYTE **outline_metrics_buf)
210 // get outline metrics of the DC, which also include the text metrics
212 unsigned long outline_metrics_size = GetOutlineTextMetricsW(hdc, 0, NULL);
213 if (outline_metrics_size == 0)
214 return outline_metrics_size;
216 *outline_metrics_buf = new BYTE[outline_metrics_size];
217 outline_metrics_size = GetOutlineTextMetricsW(hdc, outline_metrics_size, reinterpret_cast<OUTLINETEXTMETRICW *>(*outline_metrics_buf));
218 assert(outline_metrics_size != 0);
220 return outline_metrics_size;
223 unsigned long font_mgr::stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
225 // callback function, called when freetype requests font data
227 // count == 0 means seek operation
228 if (count == 0)
229 return 0;
231 const DWORD read_size = GetFontData(font_mgr_instance.get_thread_font_holder(), stream->descriptor.value, offset, buffer, count);
232 assert(read_size != GDI_ERROR);
233 assert(read_size == count);
235 return read_size;
238 void font_mgr::stream_close(FT_Stream stream)
240 // GetFontData() needs no close