+static HRESULT map_font(HDC hdc, DWORD codepages, HFONT src_font, HFONT *dst_font)
+{
+ struct font_list *font_list_entry;
+ CHARSETINFO charset_info;
+ HFONT new_font, old_font;
+ LOGFONTW font_attr;
+ DWORD mask, Csb[2];
+ BOOL found_cached;
+ UINT charset;
+ BOOL ret;
+ UINT i;
+
+ if (hdc == NULL || src_font == NULL) return E_FAIL;
+
+ for (i = 0; i < 32; i++)
+ {
+ mask = (DWORD)(1 << i);
+ if (codepages & mask)
+ {
+ Csb[0] = mask;
+ Csb[1] = 0x0;
+ ret = TranslateCharsetInfo(Csb, &charset_info, TCI_SRCFONTSIG);
+ if (!ret) continue;
+
+ /* use cached font if possible */
+ found_cached = FALSE;
+ EnterCriticalSection(&font_cache_critical);
+ LIST_FOR_EACH_ENTRY(font_list_entry, &font_cache, struct font_list, list_entry)
+ {
+ if (font_list_entry->charset == charset_info.ciCharset &&
+ font_list_entry->base_font == src_font)
+ {
+ if (dst_font != NULL)
+ *dst_font = font_list_entry->font;
+ found_cached = TRUE;
+ }
+ }
+ LeaveCriticalSection(&font_cache_critical);
+ if (found_cached) return S_OK;
+
+ GetObjectW(src_font, sizeof(font_attr), &font_attr);
+ font_attr.lfCharSet = (BYTE)charset_info.ciCharset;
+ font_attr.lfWidth = 0;
+ font_attr.lfFaceName[0] = 0;
+ new_font = CreateFontIndirectW(&font_attr);
+ if (new_font == NULL) continue;
+
+ old_font = SelectObject(hdc, new_font);
+ charset = GetTextCharset(hdc);
+ SelectObject(hdc, old_font);
+ if (charset == charset_info.ciCharset)
+ {
+ font_list_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*font_list_entry));
+ if (font_list_entry == NULL) return E_OUTOFMEMORY;
+
+ font_list_entry->base_font = src_font;
+ font_list_entry->font = new_font;
+ font_list_entry->charset = charset;
+
+ EnterCriticalSection(&font_cache_critical);
+ list_add_tail(&font_cache, &font_list_entry->list_entry);
+ LeaveCriticalSection(&font_cache_critical);
+
+ if (dst_font != NULL)
+ *dst_font = new_font;
+ return S_OK;
+ }
+ }
+ }
+
+ return E_FAIL;
+}
+
+static HRESULT release_font(HFONT font)
+{
+ struct font_list *font_list_entry;
+ HRESULT hr;
+
+ hr = E_FAIL;
+ EnterCriticalSection(&font_cache_critical);
+ LIST_FOR_EACH_ENTRY(font_list_entry, &font_cache, struct font_list, list_entry)
+ {
+ if (font_list_entry->font == font)
+ {
+ list_remove(&font_list_entry->list_entry);
+ DeleteObject(font);
+ HeapFree(GetProcessHeap(), 0, font_list_entry);
+ hr = S_OK;
+ break;
+ }
+ }
+ LeaveCriticalSection(&font_cache_critical);
+
+ return hr;
+}
+
+static HRESULT clear_font_cache(void)
+{
+ struct font_list *font_list_entry;
+ struct font_list *font_list_entry2;
+
+ EnterCriticalSection(&font_cache_critical);
+ LIST_FOR_EACH_ENTRY_SAFE(font_list_entry, font_list_entry2, &font_cache, struct font_list, list_entry)
+ {
+ list_remove(&font_list_entry->list_entry);
+ DeleteObject(font_list_entry->font);
+ HeapFree(GetProcessHeap(), 0, font_list_entry);
+ }
+ LeaveCriticalSection(&font_cache_critical);
+
+ return S_OK;
+}
+