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
23 const long font_id
= stream
->descriptor
.value
;
25 const font_info
*info
= font_man_instance
.get_font_info(font_id
);
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
);
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
);
45 int gdimm_font_man::lookup_kern(const FTC_Scaler scaler
, WORD left_glyph
, WORD right_glyph
)
50 ft_error
= FTC_Manager_LookupSize(ft_cache_man
, scaler
, &size
);
51 assert(ft_error
== 0);
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()
75 b_ret
= TlsFree(font_holder_tls_index
);
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())
107 gdimm_lock
lock(LOCK_REG_FONT
);
108 iter
= _name_to_id
.find(font_face
);
109 if (iter
== _name_to_id
.end())
112 if (_id_to_info
.empty())
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
;
141 long gdimm_font_man::link_font(const LOGFONTW
&linked_font_attr
, std::wstring
&linked_font_face
)
143 error_status_t rpc_error
;
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())
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
;
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
;
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
);
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
)
224 font_size
= GetFontData(font_holder
, table_header
, 0, NULL
, 0);
225 assert(font_size
!= GDI_ERROR
);
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
;
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
);
246 if (font_size
== GDI_ERROR
)
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
);
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
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
);
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
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
)
294 read_offset
+= buffer_len
;
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
);
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
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
)
339 read_offset
+= buffer_len
;