From 12e2cb21a2dedbd7f960cd140a2419ab0a9f21af Mon Sep 17 00:00:00 2001 From: Crend King Date: Mon, 9 Jan 2012 21:20:50 -0800 Subject: [PATCH] Use Slim Reader/Writer lock to replace CRITICAL_SECTION (better performance). Use One-Time Initialization for glyph caching to avoid duplicate glyph generation. Use thread local storage in stream I/O of font manager to avoid transient GDI font selection. --- gdipp_client/api_override.cpp | 2 +- gdipp_client/com_override.cpp | 6 +- gdipp_client/gamma.cpp | 4 +- gdipp_client/gdipp_client.cpp | 5 +- gdipp_config/render_config_cache.cpp | 4 +- gdipp_config/render_config_delta_cache.cpp | 4 +- gdipp_demo/gdipp_demo.rc | 8 +- gdipp_lib/gdipp_lib.vcproj | 12 +- gdipp_lib/lock.cpp | 34 --- gdipp_lib/lock.h | 41 ---- gdipp_lib/lru.h | 4 +- gdipp_lib/scoped_rw_lock.cpp | 35 +++ gdipp_lib/scoped_rw_lock.h | 41 ++++ gdipp_server/dc_pool.cpp | 6 +- gdipp_server/font_mgr.cpp | 164 +++++--------- gdipp_server/font_mgr.h | 15 +- gdipp_server/font_proxy.cpp | 343 ----------------------------- gdipp_server/font_proxy.h | 49 ----- gdipp_server/freetype.cpp | 3 +- gdipp_server/freetype.h | 2 +- gdipp_server/ft_renderer.cpp | 34 ++- gdipp_server/ft_renderer.h | 2 + gdipp_server/gdipp_server.rc | 8 +- gdipp_server/gdipp_server.vcproj | 80 +------ gdipp_server/ggo_renderer.cpp | 10 +- gdipp_server/ggo_renderer.h | 1 + gdipp_server/glyph_cache.cpp | 63 ++++-- gdipp_server/glyph_cache.h | 14 +- gdipp_server/os2_metrics.cpp | 10 +- gdipp_server/rpc_server.cpp | 35 +-- gdipp_server/rpc_server.h | 2 +- 31 files changed, 298 insertions(+), 743 deletions(-) delete mode 100644 gdipp_lib/lock.cpp delete mode 100644 gdipp_lib/lock.h create mode 100644 gdipp_lib/scoped_rw_lock.cpp create mode 100644 gdipp_lib/scoped_rw_lock.h delete mode 100644 gdipp_server/font_proxy.cpp delete mode 100644 gdipp_server/font_proxy.h diff --git a/gdipp_client/api_override.cpp b/gdipp_client/api_override.cpp index 01fd458..b1b8010 100644 --- a/gdipp_client/api_override.cpp +++ b/gdipp_client/api_override.cpp @@ -3,7 +3,7 @@ #include "gdipp_client/gdi_painter.h" #include "gdipp_client/global.h" #include "gdipp_client/helper.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_rpc/gdipp_rpc.h" namespace gdipp diff --git a/gdipp_client/com_override.cpp b/gdipp_client/com_override.cpp index 04e29fb..5d137be 100644 --- a/gdipp_client/com_override.cpp +++ b/gdipp_client/com_override.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "com_override.h" #include "gdipp_client/global.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -87,7 +87,7 @@ IFACEMETHODIMP CreateDxgiSurfaceRenderTarget_hook( if (DrawGlyphRun_orig == NULL) { - lock l(lock::CLIENT_COM_HOOK); + const scoped_rw_lock lock_w(scoped_rw_lock::CLIENT_COM_HOOK, false); if (DrawGlyphRun_orig == NULL) { const void **vfptr = *reinterpret_cast(*renderTarget); @@ -119,7 +119,7 @@ HRESULT WINAPI D2D1CreateFactory_hook(D2D1_FACTORY_TYPE factoryType, REFIID riid if (CreateDxgiSurfaceRenderTarget_orig == NULL) { - lock l(lock::CLIENT_COM_HOOK); + const scoped_rw_lock lock_w(scoped_rw_lock::CLIENT_COM_HOOK, false); if (CreateDxgiSurfaceRenderTarget_orig == NULL) { ID2D1Factory *pIFactory = *reinterpret_cast(ppIFactory); diff --git a/gdipp_client/gamma.cpp b/gdipp_client/gamma.cpp index 3f31275..be89ea3 100644 --- a/gdipp_client/gamma.cpp +++ b/gdipp_client/gamma.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "gamma.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -17,7 +17,7 @@ const BYTE *gamma::get_ramp(double gamma) if (iter == _gamma_ramps.end()) { // double-check lock - lock l(lock::CLIENT_GAMMA); + const scoped_rw_lock lock_w(scoped_rw_lock::CLIENT_GAMMA, false); iter = _gamma_ramps.find(gamma); if (iter == _gamma_ramps.end()) init_ramp(gamma); diff --git a/gdipp_client/gdipp_client.cpp b/gdipp_client/gdipp_client.cpp index 159736b..72961c1 100644 --- a/gdipp_client/gdipp_client.cpp +++ b/gdipp_client/gdipp_client.cpp @@ -4,7 +4,7 @@ #include "gdipp_config/constant_client.h" #include "gdipp_config/exclude_config.h" #include "gdipp_lib/helper.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -69,7 +69,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv return FALSE; gdipp::os_support_directwrite = (ver_info.dwMajorVersion >= 6); - gdipp::lock::initialize_locks(); + gdipp::scoped_rw_lock::initialize(); if (!gdipp::init_rpc_client()) return FALSE; @@ -83,7 +83,6 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv } case DLL_PROCESS_DETACH: gdipp::hook_instance.stop(); - gdipp::lock::destory_locks(); break; } diff --git a/gdipp_config/render_config_cache.cpp b/gdipp_config/render_config_cache.cpp index df48fa8..f49a054 100644 --- a/gdipp_config/render_config_cache.cpp +++ b/gdipp_config/render_config_cache.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "render_config_cache.h" #include "gdipp_lib/helper.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -42,7 +42,7 @@ const render_config_static *render_config_cache::get_font_render_config(bool bol std::map::const_iterator config_iter = _cache.find(trait); if (config_iter == _cache.end()) { - lock l(lock::CONFIG_RENDER_CACHE); + const scoped_rw_lock lock_w(scoped_rw_lock::CONFIG_RENDER_CACHE, false); config_iter = _cache.find(trait); if (config_iter == _cache.end()) { diff --git a/gdipp_config/render_config_delta_cache.cpp b/gdipp_config/render_config_delta_cache.cpp index 8f06303..289e30d 100644 --- a/gdipp_config/render_config_delta_cache.cpp +++ b/gdipp_config/render_config_delta_cache.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" #include "render_config_delta_cache.h" #include "gdipp_lib/helper.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -41,7 +41,7 @@ render_config_delta render_config_delta_cache::get_font_render_config_delta(bool std::map::const_iterator config_iter = _cache.find(trait); if (config_iter == _cache.end()) { - lock l(lock::CONFIG_RENDER_CONFIG_DELTA_CACHE); + const scoped_rw_lock lock_w(scoped_rw_lock::CONFIG_RENDER_CONFIG_DELTA_CACHE, false); config_iter = _cache.find(trait); if (config_iter == _cache.end()) { diff --git a/gdipp_demo/gdipp_demo.rc b/gdipp_demo/gdipp_demo.rc index da50e5c..4706a87 100644 --- a/gdipp_demo/gdipp_demo.rc +++ b/gdipp_demo/gdipp_demo.rc @@ -94,8 +94,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,2,0 - PRODUCTVERSION 0,9,2,0 + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -112,12 +112,12 @@ BEGIN BEGIN VALUE "CompanyName", "gdipp Project" VALUE "FileDescription", "gdipp Demo" - VALUE "FileVersion", "0, 9, 2, 0" + VALUE "FileVersion", "1, 0, 0, 0" VALUE "InternalName", "gdipp_demo" VALUE "LegalCopyright", "Copyright (C) gdipp Project 2010" VALUE "OriginalFilename", "gdipp_demo.exe" VALUE "ProductName", "gdipp Demo" - VALUE "ProductVersion", "0, 9, 2, 0" + VALUE "ProductVersion", "1, 0, 0, 0" END END BLOCK "VarFileInfo" diff --git a/gdipp_lib/gdipp_lib.vcproj b/gdipp_lib/gdipp_lib.vcproj index 070df22..456d457 100644 --- a/gdipp_lib/gdipp_lib.vcproj +++ b/gdipp_lib/gdipp_lib.vcproj @@ -351,11 +351,11 @@ > - - @@ -433,6 +429,10 @@ > + + diff --git a/gdipp_lib/lock.cpp b/gdipp_lib/lock.cpp deleted file mode 100644 index ce758c2..0000000 --- a/gdipp_lib/lock.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "stdafx.h" -#include "lock.h" - -namespace gdipp -{ - -std::vector lock::_locks; - -void lock::initialize_locks() -{ - _locks.resize(LAST_LOCK_TYPE); - for (int i = 0; i < LAST_LOCK_TYPE; ++i) - InitializeCriticalSection(&_locks[i]); -} - -void lock::destory_locks() -{ - const size_t lock_count = _locks.size(); - for (size_t i = 0; i < lock_count; ++i) - DeleteCriticalSection(&_locks[i]); -} - -lock::lock(LOCK_TYPE lock_type) -{ - _cs = &_locks[lock_type]; - EnterCriticalSection(_cs); -} - -lock::~lock() -{ - LeaveCriticalSection(_cs); -} - -} diff --git a/gdipp_lib/lock.h b/gdipp_lib/lock.h deleted file mode 100644 index fa6674d..0000000 --- a/gdipp_lib/lock.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "gdipp_lib/api.h" - -namespace gdipp -{ - -class GDIPP_API lock -{ -public: - enum LOCK_TYPE - { - CLIENT_COM_HOOK, - CLIENT_GAMMA, - CONFIG_RENDER_CACHE, - CONFIG_RENDER_CONFIG_DELTA_CACHE, - GLOBAL_DEBUG, - SERVER_DC_POOL, - SERVER_FONT_MGR, - SERVER_FREETYPE, - SERVER_GLYPH_CACHE, - SERVER_GLYPH_RUN_CACHE, - SERVER_LRU, - - LAST_LOCK_TYPE - }; - -public: - static void initialize_locks(); - static void destory_locks(); - - explicit lock(LOCK_TYPE lock_type); - ~lock(); - -private: - static std::vector _locks; - - CRITICAL_SECTION *_cs; -}; - -} diff --git a/gdipp_lib/lru.h b/gdipp_lib/lru.h index d9d07da..3d2b850 100644 --- a/gdipp_lib/lru.h +++ b/gdipp_lib/lru.h @@ -1,5 +1,7 @@ #pragma once +#include "gdipp_lib/scoped_rw_lock.h" + namespace gdipp { @@ -24,7 +26,7 @@ public: bool access(const T data, T &erased) { - lock l(lock::SERVER_LRU); + const scoped_rw_lock lock_w(scoped_rw_lock::LIB_LRU, false); bool overflow = false; diff --git a/gdipp_lib/scoped_rw_lock.cpp b/gdipp_lib/scoped_rw_lock.cpp new file mode 100644 index 0000000..d9e58b9 --- /dev/null +++ b/gdipp_lib/scoped_rw_lock.cpp @@ -0,0 +1,35 @@ +#include "stdafx.h" +#include "scoped_rw_lock.h" + +namespace gdipp +{ + +std::vector scoped_rw_lock::_srws; + +void scoped_rw_lock::initialize() +{ + _srws.resize(LAST_MONITOR_LOCATION); + for (int i = 0; i < LAST_MONITOR_LOCATION; ++i) + InitializeSRWLock(&_srws[i]); +} + +scoped_rw_lock::scoped_rw_lock(MONITOR_LOCATION cs_location, bool is_shared) +{ + _curr_srw = &_srws[cs_location]; + _is_shared = is_shared; + + if (is_shared) + AcquireSRWLockShared(_curr_srw); + else + AcquireSRWLockExclusive(_curr_srw); +} + +scoped_rw_lock::~scoped_rw_lock() +{ + if (_is_shared) + ReleaseSRWLockShared(_curr_srw); + else + ReleaseSRWLockExclusive(_curr_srw); +} + +} diff --git a/gdipp_lib/scoped_rw_lock.h b/gdipp_lib/scoped_rw_lock.h new file mode 100644 index 0000000..042b2e7 --- /dev/null +++ b/gdipp_lib/scoped_rw_lock.h @@ -0,0 +1,41 @@ +#pragma once + +#include "gdipp_lib/api.h" + +namespace gdipp +{ + +class GDIPP_API scoped_rw_lock +{ +public: + enum MONITOR_LOCATION + { + CLIENT_COM_HOOK, + CLIENT_GAMMA, + CONFIG_RENDER_CACHE, + CONFIG_RENDER_CONFIG_DELTA_CACHE, + GLOBAL_DEBUG, + LIB_LRU, + SERVER_DC_POOL, + SERVER_FONT_MGR, + SERVER_FREETYPE, + SERVER_GLYPH_CACHE, + SERVER_GLYPH_RUN_CACHE, + + LAST_MONITOR_LOCATION + }; + +public: + static void initialize(); + + explicit scoped_rw_lock(MONITOR_LOCATION srw_location, bool is_shared); + ~scoped_rw_lock(); + +private: + static std::vector _srws; + + SRWLOCK *_curr_srw; + bool _is_shared; +}; + +} diff --git a/gdipp_server/dc_pool.cpp b/gdipp_server/dc_pool.cpp index 2a26e6c..66f396a 100644 --- a/gdipp_server/dc_pool.cpp +++ b/gdipp_server/dc_pool.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "dc_pool.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" namespace gdipp { @@ -25,7 +25,7 @@ HDC dc_pool::claim() // if no resource exists, create one by calling create() of the template class // otherwise, remove one from the free resource set and add to busy set - lock l(lock::SERVER_DC_POOL); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_DC_POOL, false); HDC hdc; @@ -47,7 +47,7 @@ bool dc_pool::free(HDC hdc) { // return claimed resource back to the pool - lock l(lock::SERVER_DC_POOL); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_DC_POOL, false); std::set::const_iterator busy_iter = _busy.find(hdc); if (busy_iter == _busy.end()) diff --git a/gdipp_server/font_mgr.cpp b/gdipp_server/font_mgr.cpp index a9faac7..f71d06c 100644 --- a/gdipp_server/font_mgr.cpp +++ b/gdipp_server/font_mgr.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "font_mgr.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_server/freetype.h" #include "gdipp_server/global.h" #include "gdipp_server/helper.h" @@ -78,104 +78,100 @@ ULONG font_mgr::get_ttc_face_index(HDC font_holder, DWORD ttc_file_size) return ULONG_MAX; } -void *font_mgr::register_font(const LOGFONTW *log_font, BYTE **outline_metrics_buf, unsigned long *outline_metrics_size, HDC hdc) +font_mgr::font_mgr() +{ + _font_holder_tls_index = TlsAlloc(); + assert(_font_holder_tls_index != TLS_OUT_OF_INDEXES); +} + +font_mgr::~font_mgr() +{ + for (std::map::const_iterator iter = _font_registry.begin(); iter != _font_registry.end(); ++iter) + DeleteObject(iter->second.font_handle); + + TlsFree(_font_holder_tls_index); +} + +void *font_mgr::register_font(HDC font_holder, const LOGFONTW *log_font, BYTE **outline_metrics_buf, unsigned long *outline_metrics_size) { // create a font with supplied LOGFONT and retrieve related information bool b_ret; - font_entry *font_id = NULL; - HDC font_holder; std::wstring font_face; std::map::iterator font_iter; - // whether delete the created font when exiting (when anything failed or font existed) - bool delete_font = true; - const HFONT hfont = CreateFontIndirectW(log_font); if (hfont == NULL) return NULL; - /* - if an HDC is supplied, use the HDC to select font - otherwise, claim a temporary HDC from DC pool and use it - temporary HDC will be freed before exiting function - */ - if (hdc == NULL) - { - font_holder = dc_pool_instance.claim(); - assert(font_holder != NULL); - } - else - { - font_holder = hdc; - SelectObject(font_holder, hfont); - } + SelectObject(font_holder, hfont); *outline_metrics_size = get_dc_outline_metrics(font_holder, outline_metrics_buf); if (*outline_metrics_size == 0) - goto clean_up_and_return; + { + DeleteObject(hfont); + return NULL; + } const OUTLINETEXTMETRICW *outline_metrics = reinterpret_cast(*outline_metrics_buf); font_face = metric_face_name(outline_metrics); font_iter = _font_registry.find(font_face); if (font_iter == _font_registry.end()) { - lock l(lock::SERVER_FONT_MGR); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FONT_MGR, false); font_iter = _font_registry.find(font_face); if (font_iter == _font_registry.end()) { os2_metrics os2; b_ret = os2.init(font_holder); if (!b_ret) - goto clean_up_and_return; + { + DeleteObject(hfont); + return NULL; + } DWORD table_header; DWORD font_size = get_font_size(font_holder, &table_header); if (font_size == GDI_ERROR) - goto clean_up_and_return; + { + DeleteObject(hfont); + return NULL; + } DWORD face_index = 0; if (table_header != 0) { face_index = get_ttc_face_index(font_holder, font_size); if (face_index == ULONG_MAX) - goto clean_up_and_return; + { + DeleteObject(hfont); + return NULL; + } } - const font_entry new_font_data = {}; - _font_registry[font_face] = new_font_data; - font_id = &_font_registry[font_face]; - - font_id->font_handle = hfont; - font_id->os2 = os2; - font_id->face_index = face_index; - font_id->table_header = table_header; + const std::pair::iterator, bool> insert_ret = _font_registry.insert(std::pair(font_face, font_entry())); + assert(insert_ret.second); + font_iter = insert_ret.first; - font_id->stream.size = font_size; - font_id->stream.descriptor.pointer = font_id; - font_id->stream.read = font_mgr::stream_io; - font_id->stream.close = font_mgr::stream_close; + font_iter->second.font_handle = hfont; + font_iter->second.os2 = os2; + font_iter->second.face_index = face_index; + font_iter->second.table_header = table_header; - delete_font = false; + font_iter->second.stream.size = font_size; + // need the table header to retrieve font data (see stream_io()) + font_iter->second.stream.descriptor.value = table_header; + font_iter->second.stream.read = font_mgr::stream_io; + font_iter->second.stream.close = font_mgr::stream_close; - // goto is require for double checking lock - // destructor of the lock will be called before jumping - goto clean_up_and_return; + return &font_iter->second; } } - font_id = &font_iter->second; - -clean_up_and_return: - // if anything failed, delete created font - if (delete_font) - DeleteObject(hfont); - - if (hdc == NULL) - dc_pool_instance.free(font_holder); - - return font_id; + // font has been created before + DeleteObject(hfont); + return &font_iter->second; } HFONT font_mgr::select_font(void *font_id, HDC hdc) const @@ -190,64 +186,26 @@ ULONG font_mgr::lookup_face_index(void *font_id) const return curr_font->face_index; } -DWORD font_mgr::lookup_font_data(void *font_id, DWORD table, DWORD offset, LPVOID data_buf, DWORD buf_size, HDC hdc) const +const os2_metrics *font_mgr::lookup_os2_metrics(void *font_id) const { const font_entry *curr_font = reinterpret_cast(font_id); - HDC font_holder; - - if (hdc == NULL) - { - font_holder = dc_pool_instance.claim(); - assert(font_holder != NULL); - } - else - { - font_holder = hdc; - } - SelectObject(font_holder, curr_font->font_handle); - - const DWORD data_size = GetFontData(font_holder, table, offset, data_buf, buf_size); - - if (hdc == NULL) - dc_pool_instance.free(font_holder); - - return data_size; + return &curr_font->os2; } -DWORD font_mgr::lookup_glyph_indices(void *font_id, const wchar_t *str, int count, unsigned short *gi, HDC hdc) const +FT_Stream font_mgr::lookup_stream(void *font_id) const { - const font_entry *curr_font = reinterpret_cast(font_id); - HDC font_holder; - - if (hdc == NULL) - { - font_holder = dc_pool_instance.claim(); - assert(font_holder != NULL); - } - else - { - font_holder = hdc; - } - SelectObject(font_holder, curr_font->font_handle); - - const DWORD converted = GetGlyphIndices(font_holder, str, count, gi, GGI_MARK_NONEXISTING_GLYPHS); - - if (hdc == NULL) - dc_pool_instance.free(font_holder); - - return converted; + font_entry *curr_font = reinterpret_cast(font_id); + return &curr_font->stream; } -const os2_metrics *font_mgr::lookup_os2_metrics(void *font_id) const +HDC font_mgr::get_thread_font_holder() const { - const font_entry *curr_font = reinterpret_cast(font_id); - return &curr_font->os2; + return reinterpret_cast(TlsGetValue(_font_holder_tls_index)); } -FT_Stream font_mgr::lookup_stream(void *font_id) const +BOOL font_mgr::set_thread_font_holder(HDC font_holder) const { - font_entry *curr_font = reinterpret_cast(font_id); - return &curr_font->stream; + return TlsSetValue(_font_holder_tls_index, font_holder); } unsigned long font_mgr::get_dc_outline_metrics(HDC hdc, BYTE **outline_metrics_buf) @@ -273,8 +231,8 @@ unsigned long font_mgr::stream_io(FT_Stream stream, unsigned long offset, unsign if (count == 0) return 0; - font_entry *font_id = reinterpret_cast(stream->descriptor.pointer); - const DWORD read_size = font_mgr_instance.lookup_font_data(font_id, font_id->table_header, offset, buffer, count); + const DWORD read_size = GetFontData(font_mgr_instance.get_thread_font_holder(), stream->descriptor.value, offset, buffer, count); + assert(read_size != GDI_ERROR); assert(read_size == count); return read_size; diff --git a/gdipp_server/font_mgr.h b/gdipp_server/font_mgr.h index 5862850..f5e6103 100644 --- a/gdipp_server/font_mgr.h +++ b/gdipp_server/font_mgr.h @@ -17,20 +17,24 @@ class font_mgr public: static DWORD get_font_size(HDC font_holder, DWORD *table_header); static ULONG get_ttc_face_index(HDC font_holder, DWORD ttc_file_size); - - void *register_font(const LOGFONTW *log_font, BYTE **outline_metrics_buf, unsigned long *outline_metrics_size, HDC hdc = NULL); + + font_mgr(); + ~font_mgr(); + + void *register_font(HDC font_holder, const LOGFONTW *log_font, BYTE **outline_metrics_buf, unsigned long *outline_metrics_size); HFONT select_font(void *font_id, HDC hdc) const; ULONG lookup_face_index(void *font_id) const; - DWORD lookup_font_data(void *font_id, DWORD table, DWORD offset, LPVOID data_buf, DWORD buf_size, HDC hdc = NULL) const; - DWORD lookup_glyph_indices(void *font_id, const wchar_t *str, int count, unsigned short *gi, HDC hdc = NULL) const; const os2_metrics *lookup_os2_metrics(void *font_id) const; FT_Stream lookup_stream(void *font_id) const; + HDC get_thread_font_holder() const; + BOOL set_thread_font_holder(HDC font_holder) const; + private: struct font_entry { - // all fields are font-specific invariants + // all fields are font-specific and thread-safe invariants HFONT font_handle; os2_metrics os2; @@ -46,6 +50,7 @@ private: static void stream_close(FT_Stream stream); std::map _font_registry; + DWORD _font_holder_tls_index; }; } diff --git a/gdipp_server/font_proxy.cpp b/gdipp_server/font_proxy.cpp deleted file mode 100644 index a8c76fd..0000000 --- a/gdipp_server/font_proxy.cpp +++ /dev/null @@ -1,343 +0,0 @@ -#include "stdafx.h" -#include "font_man.h" -#include "freetype.h" - -#define TTCF_TABLE_TAG mmioFOURCC('t', 't', 'c', 'f') - -// little-endian <-> big-endian -#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) -#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) - -DWORD font_holder_tls_index = 0; - -unsigned long gdimm_font_man::stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) -{ - // callback function, called when freetype requests font data - - error_status_t rpc_error; - - // count == 0 means seek operation - if (count == 0) - return 0; - - const long font_id = stream->descriptor.value; - - const font_info *info = font_man_instance.get_font_info(font_id); - assert(info != NULL); - - DWORD read_size; - if (font_id < 0) - { - HDC font_holder = reinterpret_cast(TlsGetValue(font_holder_tls_index)); - assert(font_holder != NULL); - read_size = GetFontData(font_holder, info->table_header, offset, buffer, count); - } - else - { - rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, info->table_header, offset, buffer, count, &read_size); - assert(rpc_error == 0); - } - assert(read_size == count); - - return read_size; -} - -int gdimm_font_man::lookup_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph) -{ - FT_Error ft_error; - - FT_Size size; - ft_error = FTC_Manager_LookupSize(ft_cache_man, scaler, &size); - assert(ft_error == 0); - - FT_Vector delta; - ft_error = FT_Get_Kerning(size->face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &delta); - assert(ft_error == 0); - - return int_from_26dot6(delta.x); -} - -void gdimm_font_man::stream_close(FT_Stream stream) -{ - // GetFontData() needs no close -} - -gdimm_font_man::gdimm_font_man() -{ - font_holder_tls_index = TlsAlloc(); - assert(font_holder_tls_index != TLS_OUT_OF_INDEXES); -} - -gdimm_font_man::~gdimm_font_man() -{ - BOOL b_ret; - - b_ret = TlsFree(font_holder_tls_index); - assert(b_ret); -} - -const font_info * gdimm_font_man::get_font_info(long font_id) -{ - return &_id_to_info[font_id]; -} - -FT_Stream gdimm_font_man::lookup_stream(long font_id) -{ - return &_id_to_info[font_id].stream; -} - -ULONG gdimm_font_man::lookup_face_index(long font_id) -{ - return _id_to_info[font_id].face_index; -} - -const os2_metrics *gdimm_font_man::lookup_os2_metrics(long font_id) -{ - return &_id_to_info[font_id].os2_metrics; -} - -long gdimm_font_man::register_font(HDC font_holder, const wchar_t *font_face) -{ - TlsSetValue(font_holder_tls_index, font_holder); - - std::map::const_iterator iter = _name_to_id.find(font_face); - if (iter == _name_to_id.end()) - { - // double-check lock - gdimm_lock lock(LOCK_REG_FONT); - iter = _name_to_id.find(font_face); - if (iter == _name_to_id.end()) - { - long new_font_id; - if (_id_to_info.empty()) - new_font_id = -1; - else - new_font_id = (long) _id_to_info.begin()->first - 1; - - font_info new_font_data = {}; - new_font_data.stream.size = get_font_size(font_holder, new_font_data.table_header); - new_font_data.stream.descriptor.value = new_font_id; - new_font_data.stream.read = gdimm_font_man::stream_io; - new_font_data.stream.close = gdimm_font_man::stream_close; - - if (new_font_data.table_header != 0) - { - new_font_data.face_index = get_ttc_face_index(font_holder, new_font_data.stream.size); - assert(new_font_data.face_index != ULONG_MAX); - } - - new_font_data.os2_metrics.init(font_holder); - - _name_to_id[font_face] = new_font_id; - _id_to_info[new_font_id] = new_font_data; - - return new_font_id; - } - } - - return iter->second; -} - -long gdimm_font_man::link_font(const LOGFONTW &linked_font_attr, std::wstring &linked_font_face) -{ - error_status_t rpc_error; - long font_id; - - rpc_error = gdipp_rpc_register_font(h_gdipp_rpc, reinterpret_cast(&linked_font_attr), sizeof(linked_font_attr), reinterpret_cast(&font_id)); - assert(rpc_error == 0 && font_id >= 0); - - std::map::const_iterator iter = _id_to_info.find(font_id); - if (iter == _id_to_info.end()) - { - // double-check lock - gdimm_lock lock(LOCK_REG_FONT); - iter = _id_to_info.find(font_id); - if (iter == _id_to_info.end()) - { - font_info new_font_data = {}; - new_font_data.stream.size = get_font_size(font_id, new_font_data.table_header); - new_font_data.stream.descriptor.value = font_id; - new_font_data.stream.read = gdimm_font_man::stream_io; - new_font_data.stream.close = gdimm_font_man::stream_close; - - if (new_font_data.table_header != 0) - { - new_font_data.face_index = get_ttc_face_index(font_id, new_font_data.stream.size); - assert(new_font_data.face_index != ULONG_MAX); - } - - new_font_data.os2_metrics.init(font_id); - - _id_to_info[font_id] = new_font_data; - } - } - - DWORD metric_buf_size; - - rpc_error = gdipp_rpc_get_font_metrics_size(h_gdipp_rpc, font_id, &metric_buf_size); - assert(rpc_error == 0 && metric_buf_size > 0); - - byte *font_metrics = new byte[metric_buf_size]; - - rpc_error = gdipp_rpc_get_font_metrics_data(h_gdipp_rpc, font_id, font_metrics, metric_buf_size, &metric_buf_size); - assert(rpc_error == 0 && metric_buf_size > 0); - - linked_font_face = metric_face_name(font_metrics); - - delete[] font_metrics; - - return font_id; -} - -void gdimm_font_man::get_glyph_indices(long font_id, const wchar_t *str, int count, wchar_t *gi) -{ - error_status_t rpc_error; - DWORD converted; - - if (font_id < 0) - { - HDC font_holder = reinterpret_cast(TlsGetValue(font_holder_tls_index)); - assert(font_holder != NULL); - converted = GetGlyphIndices(font_holder, str, count, reinterpret_cast(gi), GGI_MARK_NONEXISTING_GLYPHS); - } - else - { - rpc_error = gdipp_rpc_get_glyph_indices(h_gdipp_rpc, font_id, str, count, reinterpret_cast(gi), &converted); - assert(rpc_error == 0); - } - assert(converted == count); -} - -DWORD gdimm_font_man::get_font_size(HDC font_holder, DWORD &table_header) -{ - table_header = TTCF_TABLE_TAG; - - /* - try to get font file size with ttcf tag first - if succeeds, the font face is part of a TTC file - otherwise, the font face is a standalone TrueType font file - */ - DWORD font_size = GetFontData(font_holder, table_header, 0, NULL, 0); - if (font_size == GDI_ERROR) - { - table_header = 0; - font_size = GetFontData(font_holder, table_header, 0, NULL, 0); - assert(font_size != GDI_ERROR); - } - - return font_size; -} - -DWORD gdimm_font_man::get_font_size(long font_id, DWORD &table_header) -{ - error_status_t rpc_error; - table_header = TTCF_TABLE_TAG; - DWORD font_size; - - /* - try to get font file size with ttcf tag first - if succeeds, the font face is part of a TTC file - otherwise, the font face is a standalone TrueType font file - */ - rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, table_header, 0, &font_size); - if (rpc_error != 0) - return 0; - - if (font_size == GDI_ERROR) - { - table_header = 0; - rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, table_header, 0, &font_size); - assert(rpc_error == 0 && font_size != GDI_ERROR); - } - - return font_size; -} - -ULONG gdimm_font_man::get_ttc_face_index(HDC font_holder, DWORD ttc_file_size) -{ - // get the index of the current face in its TTC file - // by comparing its start offset retrieved from GetFontData and from the TTC header - - // pre-condition: the font file contains TTC header - - DWORD read_size; - - // start offset of the current face - DWORD face_start = GetFontData(font_holder, 0, 0, NULL, 0); - assert(face_start != GDI_ERROR); - face_start = ttc_file_size - face_start; - - DWORD read_offset = sizeof(DWORD) + sizeof(FIXED); - ULONG face_count; - DWORD buffer_len = sizeof(face_count); - - // number of face records in the TTC header - read_size = GetFontData(font_holder, TTCF_TABLE_TAG, read_offset, &face_count, buffer_len); - assert(read_size == buffer_len); - - // TrueType font data uses big-endian, while mainstream Windows uses little-endian platforms - face_count = SWAPLONG(face_count); - read_offset += buffer_len; - - for (ULONG i = 0; i < face_count; ++i) - { - // start offset of the current record - DWORD curr_start; - buffer_len = sizeof(curr_start); - read_size = GetFontData(font_holder, TTCF_TABLE_TAG, read_offset, &curr_start, buffer_len); - assert(read_size == buffer_len); - curr_start = SWAPLONG(curr_start); - - if (curr_start == face_start) - return i; - - read_offset += buffer_len; - } - - return ULONG_MAX; -} - -ULONG gdimm_font_man::get_ttc_face_index(long font_id, DWORD ttc_file_size) -{ - // get the index of the current face in its TTC file - // by comparing its start offset retrieved from GetFontData and from the TTC header - - // pre-condition: the font file contains TTC header - - error_status_t rpc_error; - DWORD face_start, read_size; - - // start offset of the current face - rpc_error = gdipp_rpc_get_font_data_size(h_gdipp_rpc, font_id, 0, 0, &face_start); - assert(rpc_error == 0 && face_start != GDI_ERROR); - face_start = ttc_file_size - face_start; - - DWORD read_offset = sizeof(DWORD) + sizeof(FIXED); - ULONG face_count; - DWORD buffer_len = sizeof(face_count); - - // number of face records in the TTC header - rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, TTCF_TABLE_TAG, read_offset, reinterpret_cast(&face_count), buffer_len, &read_size); - assert(rpc_error == 0 && read_size == buffer_len); - - // TrueType font data uses big-endian, while mainstream Windows uses little-endian platforms - face_count = SWAPLONG(face_count); - read_offset += buffer_len; - - for (ULONG i = 0; i < face_count; ++i) - { - // start offset of the current record - DWORD curr_start; - buffer_len = sizeof(curr_start); - rpc_error = gdipp_rpc_get_font_data(h_gdipp_rpc, font_id, TTCF_TABLE_TAG, read_offset, reinterpret_cast(&curr_start), buffer_len, &read_size); - assert(rpc_error == 0 && read_size == buffer_len); - curr_start = SWAPLONG(curr_start); - - if (curr_start == face_start) - return i; - - read_offset += buffer_len; - } - - return ULONG_MAX; -} diff --git a/gdipp_server/font_proxy.h b/gdipp_server/font_proxy.h deleted file mode 100644 index d11f4bb..0000000 --- a/gdipp_server/font_proxy.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -class gdimm_font_man -{ - /* - font manager manages two kinds of font: local font and remote font - - registered fonts are created outside gdipp - they are considered temporary, not managed by the font manager - registered fonts have non-negative font id - - linked fonts are created by gdipp for font linking - every linked font are kept alive until the font storage is destructed - linked fonts have negative font id - */ - -public: - static unsigned long stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count); - static void stream_close(FT_Stream stream); - static int lookup_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph); - - gdimm_font_man(); - ~gdimm_font_man(); - - const font_info *get_font_info(long font_id); - FT_Stream lookup_stream(long font_id); - ULONG lookup_face_index(long font_id); - const os2_metrics *lookup_os2_metrics(long font_id); - - long register_font(HDC font_holder, const wchar_t *font_face); - long link_font(const LOGFONTW &linked_font_attr, std::wstring &linked_font_face); - void get_glyph_indices(long font_id, const wchar_t *str, int count, wchar_t *gi); - -private: - static DWORD get_font_size(HDC font_holder, DWORD &table_header); - static DWORD get_font_size(long font_id, DWORD &table_header); - static ULONG get_ttc_face_index(HDC font_holder, DWORD ttc_file_size); - static ULONG get_ttc_face_index(long font_id, DWORD ttc_file_size); - - // face name -> font id - // we use this std::map because FreeType callback only have face id - std::map _name_to_id; - // font id -> font info - // we use this std::map because std::vector internally free and re-allocate existing entries - // pointers become invalid - std::map _id_to_info; -}; diff --git a/gdipp_server/freetype.cpp b/gdipp_server/freetype.cpp index d7e0b54..bff8a58 100644 --- a/gdipp_server/freetype.cpp +++ b/gdipp_server/freetype.cpp @@ -3,6 +3,7 @@ #include "gdipp_config/constant_server.h" #include "gdipp_server/global.h" #include "gdipp_server/helper.h" +#include "gdipp_server/ft_renderer.h" namespace gdipp { @@ -58,7 +59,7 @@ FT_Error face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer reque return FT_Open_Face(library, &args, font_mgr_instance.lookup_face_index(face_id), aface); } -int get_freetype_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph) +int freetype_get_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph) { FT_Error ft_error; diff --git a/gdipp_server/freetype.h b/gdipp_server/freetype.h index 6fa2b6e..e8bd51f 100644 --- a/gdipp_server/freetype.h +++ b/gdipp_server/freetype.h @@ -11,7 +11,7 @@ extern FT_Glyph empty_outline_glyph; void initialize_freetype(); void destroy_freetype(); FT_Error face_requester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface); -int get_freetype_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph); +int freetype_get_kern(const FTC_Scaler scaler, WORD left_glyph, WORD right_glyph); FT_Glyph make_empty_outline_glyph(); } diff --git a/gdipp_server/ft_renderer.cpp b/gdipp_server/ft_renderer.cpp index 12d8855..772ba0a 100644 --- a/gdipp_server/ft_renderer.cpp +++ b/gdipp_server/ft_renderer.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "ft_renderer.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_server/freetype.h" #include "gdipp_server/global.h" #include "gdipp_server/helper.h" @@ -117,7 +117,7 @@ bool ft_renderer::generate_outline_glyph(FT_Glyph *glyph, { // the FreeType function seems not thread-safe - lock l(lock::SERVER_FREETYPE); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FREETYPE, false); ft_error = FTC_ImageCache_LookupScaler(ft_glyph_cache, scaler, load_flags, glyph_index, &cached_glyph, NULL); if (ft_error != 0) return NULL; @@ -183,7 +183,7 @@ const FT_Glyph ft_renderer::generate_bitmap_glyph(WORD glyph_index, // outline -> bitmap conversion { // the FreeType function seems not thread-safe - lock l(lock::SERVER_FREETYPE); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FREETYPE, false); ft_error = FT_Glyph_To_Bitmap(&glyph, render_mode, NULL, is_local_glyph); if (ft_error != 0) return NULL; @@ -241,7 +241,7 @@ bool ft_renderer::generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT } else if (curr_render_config->kerning && i > 0 && !request_outline) { - ctrl_box.left = get_freetype_kern(&scaler, lpString[i-1], lpString[i]); + ctrl_box.left = freetype_get_kern(&scaler, lpString[i-1], lpString[i]); ctrl_box.right = ctrl_box.left; } @@ -265,7 +265,7 @@ bool ft_renderer::generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT while (true) { - font_mgr_instance.lookup_glyph_indices(scaler.face_id, final_string.data(), c, &glyph_indices[0]); + GetGlyphIndices(_curr_font_holder, final_string.data(), c, &glyph_indices[0], GGI_MARK_NONEXISTING_GLYPHS); std::vector::iterator glyph_iter; std::vector::iterator ctrl_iter, black_iter; @@ -297,7 +297,7 @@ bool ft_renderer::generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT } else if (curr_render_config->kerning && i > 0 && !request_outline) { - ctrl_iter->left = get_freetype_kern(&scaler, glyph_indices[i-1], glyph_indices[i]); + ctrl_iter->left = freetype_get_kern(&scaler, glyph_indices[i-1], glyph_indices[i]); ctrl_iter->right = ctrl_iter->left; } } @@ -332,7 +332,7 @@ bool ft_renderer::generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT BYTE *curr_outline_metrics_buf; unsigned long curr_outline_metrics_size; - scaler.face_id = font_mgr_instance.register_font(&linked_log_font, &curr_outline_metrics_buf, &curr_outline_metrics_size); + scaler.face_id = font_mgr_instance.register_font(_curr_font_holder, &linked_log_font, &curr_outline_metrics_buf, &curr_outline_metrics_size); assert(scaler.face_id != NULL); // reload metrics for the linked font @@ -369,6 +369,8 @@ bool ft_renderer::generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT curr_load_flags = make_load_flags(curr_render_config, _session->render_mode); } + + dc_pool_instance.free(_curr_font_holder); } return true; @@ -378,7 +380,25 @@ bool ft_renderer::render(bool is_glyph_index, LPCWSTR lpString, UINT c, glyph_ru { bool b_ret; + if (is_glyph_index) + { + _curr_font_holder = _session->font_holder; + } + else + { + // font link is possible + // we need an extra DC to hold linked font and not affect the session font holder + _curr_font_holder = dc_pool_instance.claim(); + assert(_curr_font_holder != NULL); + font_mgr_instance.select_font(_session->font_id, _curr_font_holder); + } + font_mgr_instance.set_thread_font_holder(_curr_font_holder); + b_ret = generate_glyph_run(is_glyph_index, lpString, c, new_glyph_run, false); + + if (!is_glyph_index) + dc_pool_instance.free(_curr_font_holder); + if (!b_ret) return false; diff --git a/gdipp_server/ft_renderer.h b/gdipp_server/ft_renderer.h index a00a53b..5c4ee00 100644 --- a/gdipp_server/ft_renderer.h +++ b/gdipp_server/ft_renderer.h @@ -33,6 +33,8 @@ private: bool generate_glyph_run(bool is_glyph_index, LPCWSTR lpString, UINT c, glyph_run *new_glyph_run, bool request_outline); bool render(bool is_glyph_index, LPCWSTR lpString, UINT c, glyph_run *new_glyph_run); + + HDC _curr_font_holder; }; } diff --git a/gdipp_server/gdipp_server.rc b/gdipp_server/gdipp_server.rc index f4506d5..3d6e3ce 100644 --- a/gdipp_server/gdipp_server.rc +++ b/gdipp_server/gdipp_server.rc @@ -61,8 +61,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,9,2,0 - PRODUCTVERSION 0,9,2,0 + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -79,12 +79,12 @@ BEGIN BEGIN VALUE "CompanyName", "gdipp Project" VALUE "FileDescription", "gdipp Server" - VALUE "FileVersion", "0, 9, 2, 0" + VALUE "FileVersion", "1, 0, 0, 0" VALUE "InternalName", "gdipp_server" VALUE "LegalCopyright", "Copyright (C) 2010" VALUE "OriginalFilename", "gdipp_server.exe" VALUE "ProductName", "gdipp Server" - VALUE "ProductVersion", "0, 9, 2, 0" + VALUE "ProductVersion", "1, 0, 0, 0" END END BLOCK "VarFileInfo" diff --git a/gdipp_server/gdipp_server.vcproj b/gdipp_server/gdipp_server.vcproj index 3f09385..d568687 100644 --- a/gdipp_server/gdipp_server.vcproj +++ b/gdipp_server/gdipp_server.vcproj @@ -411,42 +411,6 @@ > - - - - - - - - - - - - - - @@ -455,11 +419,10 @@ > - - - - - - - - - - - - - - diff --git a/gdipp_server/ggo_renderer.cpp b/gdipp_server/ggo_renderer.cpp index 55f7b88..41ef309 100644 --- a/gdipp_server/ggo_renderer.cpp +++ b/gdipp_server/ggo_renderer.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "ggo_renderer.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_server/freetype.h" #include "gdipp_server/global.h" #include "gdipp_server/helper.h" @@ -152,7 +152,7 @@ void ggo_renderer::outline_ggo_to_ft(DWORD ggo_outline_buf_len, const BYTE *ggo_ bool ggo_renderer::get_glyph_metrics(wchar_t ch, GLYPHMETRICS &glyph_metrics) const { - DWORD outline_buf_len = GetGlyphOutline(_session->hdc, ch, (_ggo_format | GGO_METRICS), &glyph_metrics, 0, NULL, &_matrix); + DWORD outline_buf_len = GetGlyphOutline(_session->font_holder, ch, (_ggo_format | GGO_METRICS), &glyph_metrics, 0, NULL, &_matrix); return (outline_buf_len != GDI_ERROR); } @@ -164,7 +164,7 @@ const FT_Glyph ggo_renderer::outline_to_bitmap(wchar_t ch, GLYPHMETRICS &glyph_m FT_OutlineGlyphRec outline_glyph = {*empty_outline_glyph, {}}; outline_glyph.root.format = FT_GLYPH_FORMAT_OUTLINE; - DWORD outline_buf_len = GetGlyphOutline(_session->hdc, ch, _ggo_format, &glyph_metrics, 0, NULL, &_matrix); + DWORD outline_buf_len = GetGlyphOutline(_session->font_holder, ch, _ggo_format, &glyph_metrics, 0, NULL, &_matrix); assert(outline_buf_len != GDI_ERROR); if (outline_buf_len == 0) @@ -178,7 +178,7 @@ const FT_Glyph ggo_renderer::outline_to_bitmap(wchar_t ch, GLYPHMETRICS &glyph_m else { BYTE *outline_buf = new BYTE[outline_buf_len]; - outline_buf_len = GetGlyphOutline(_session->hdc, ch, _ggo_format, &glyph_metrics, outline_buf_len, outline_buf, &_matrix); + outline_buf_len = GetGlyphOutline(_session->font_holder, ch, _ggo_format, &glyph_metrics, outline_buf_len, outline_buf, &_matrix); assert(outline_buf_len != GDI_ERROR); std::vector curve_points; @@ -219,7 +219,7 @@ const FT_Glyph ggo_renderer::outline_to_bitmap(wchar_t ch, GLYPHMETRICS &glyph_m { // the FreeType function seems not thread-safe - lock l(lock::SERVER_FREETYPE); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_FREETYPE, false); ft_error = FT_Glyph_To_Bitmap(&generic_glyph, _session->render_mode, NULL, false); if (ft_error != 0) return NULL; diff --git a/gdipp_server/ggo_renderer.h b/gdipp_server/ggo_renderer.h index 0872f7b..4844186 100644 --- a/gdipp_server/ggo_renderer.h +++ b/gdipp_server/ggo_renderer.h @@ -9,6 +9,7 @@ class ggo_renderer : public renderer { public: explicit ggo_renderer(rpc_session *render_session); + bool render(bool is_glyph_index, LPCWSTR lpString, UINT c, glyph_run *new_glyph_run); private: diff --git a/gdipp_server/glyph_cache.cpp b/gdipp_server/glyph_cache.cpp index 744443a..42e5fa2 100644 --- a/gdipp_server/glyph_cache.cpp +++ b/gdipp_server/glyph_cache.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "glyph_cache.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_server/global.h" namespace gdipp @@ -35,8 +35,13 @@ glyph_cache::char_id_type glyph_cache::get_char_id(uint128_t render_trait, FT_UI glyph_cache::~glyph_cache() { - for (std::map::const_iterator glyph_iter = _glyph_store.begin(); glyph_iter != _glyph_store.end(); ++glyph_iter) - FT_Done_Glyph(glyph_iter->second); + for (std::map::iterator glyph_iter = _glyph_store.begin(); glyph_iter != _glyph_store.end(); ++glyph_iter) + { + BOOL pending; + FT_Glyph glyph; + InitOnceBeginInitialize(&glyph_iter->second, INIT_ONCE_CHECK_ONLY, &pending, reinterpret_cast(&glyph)); + FT_Done_Glyph(glyph); + } for (std::map::const_iterator str_iter = _glyph_run_store.begin(); str_iter != _glyph_run_store.end(); ++str_iter) { @@ -50,32 +55,48 @@ void glyph_cache::initialize() _glyph_run_lru.resize(min(1 << server_cache_size, 16777216)); } -const FT_Glyph glyph_cache::lookup_glyph(char_id_type char_id) const +const FT_Glyph glyph_cache::lookup_glyph(char_id_type char_id) { - std::map::const_iterator glyph_iter = _glyph_store.find(char_id); - if (glyph_iter == _glyph_store.end()) + std::map::iterator glyph_iter; + { - lock l(lock::SERVER_GLYPH_CACHE); + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_CACHE, false); + glyph_iter = _glyph_store.find(char_id); if (glyph_iter == _glyph_store.end()) - return NULL; + { + const std::pair::iterator, bool> insert_ret = _glyph_store.insert(std::pair(char_id, INIT_ONCE())); + assert(insert_ret.second); + glyph_iter = insert_ret.first; + InitOnceInitialize(&glyph_iter->second); + } } - - return glyph_iter->second; + + FT_Glyph glyph = NULL; + BOOL pending; + InitOnceBeginInitialize(&glyph_iter->second, 0, &pending, reinterpret_cast(&glyph)); + assert((glyph == NULL) == pending); + + return glyph; } bool glyph_cache::store_glyph(char_id_type char_id, const FT_Glyph glyph) { - lock l(lock::SERVER_GLYPH_CACHE); + std::map::iterator glyph_iter; - const std::pair::const_iterator, bool> glyph_insert_ret = _glyph_store.insert(std::pair(char_id, glyph)); + { + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_CACHE, false); + + glyph_iter = _glyph_store.find(char_id); + } - return glyph_insert_ret.second; + InitOnceComplete(&glyph_iter->second, (glyph == NULL ? INIT_ONCE_INIT_FAILED : 0), glyph); + return glyph != NULL; } -const glyph_run *glyph_cache::lookup_glyph_run(uint128_t string_id, uint128_t render_trait) const +const glyph_run *glyph_cache::lookup_glyph_run(string_id_type string_id, uint128_t render_trait) const { - lock l(lock::SERVER_GLYPH_RUN_CACHE); + const scoped_rw_lock lock_r(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, true); std::map::const_iterator str_iter = _glyph_run_store.find(string_id); if (str_iter == _glyph_run_store.end()) @@ -88,12 +109,12 @@ const glyph_run *glyph_cache::lookup_glyph_run(uint128_t string_id, uint128_t re return trait_iter->second; } -bool glyph_cache::store_glyph_run(uint128_t string_id, uint128_t render_trait, glyph_run *a_glyph_run) +bool glyph_cache::store_glyph_run(string_id_type string_id, uint128_t render_trait, glyph_run *a_glyph_run) { - lock l(lock::SERVER_GLYPH_RUN_CACHE); - bool b_ret; - uint128_t erased_str; + string_id_type erased_str; + + const scoped_rw_lock lock_w(scoped_rw_lock::SERVER_GLYPH_RUN_CACHE, false); b_ret = _glyph_run_lru.access(string_id, erased_str); if (b_ret) @@ -101,7 +122,7 @@ bool glyph_cache::store_glyph_run(uint128_t string_id, uint128_t render_trait, g // the string is evicted from LRU cache // erase all cached glyph run that is under the evicted string ID - std::map::iterator str_iter = _glyph_run_store.find(erased_str); + std::map::iterator str_iter = _glyph_run_store.find(erased_str); assert(str_iter != _glyph_run_store.end()); for (trait_to_run_map::const_iterator trait_iter = str_iter->second.begin(); trait_iter != str_iter->second.end(); ++trait_iter) @@ -111,7 +132,7 @@ bool glyph_cache::store_glyph_run(uint128_t string_id, uint128_t render_trait, g } // after eviction, insert new glyph_run - const std::pair::iterator, bool> str_insert_ret = _glyph_run_store.insert(std::pair(string_id, trait_to_run_map())); + const std::pair::iterator, bool> str_insert_ret = _glyph_run_store.insert(std::pair(string_id, trait_to_run_map())); const std::pair trait_insert_ret = str_insert_ret.first->second.insert(std::pair(render_trait, a_glyph_run)); return trait_insert_ret.second; diff --git a/gdipp_server/glyph_cache.h b/gdipp_server/glyph_cache.h index 81cc6f3..1a40223 100644 --- a/gdipp_server/glyph_cache.h +++ b/gdipp_server/glyph_cache.h @@ -11,6 +11,7 @@ class glyph_cache public: typedef uint128_t string_id_type; typedef uint128_t char_id_type; + typedef std::pair glyph_run_id_type; static string_id_type get_string_id(const wchar_t *string, unsigned int count, bool is_glyph_index); static char_id_type get_char_id(uint128_t render_trait, FT_UInt index, bool is_glyph_index); @@ -18,23 +19,24 @@ public: ~glyph_cache(); void initialize(); - const FT_Glyph lookup_glyph(char_id_type char_id) const; + + const FT_Glyph lookup_glyph(char_id_type char_id); bool store_glyph(char_id_type char_id, const FT_Glyph glyph); - const glyph_run *lookup_glyph_run(uint128_t string_id, uint128_t render_trait) const; - bool store_glyph_run(uint128_t string_id, uint128_t render_trait, glyph_run *a_glyph_run); + const glyph_run *lookup_glyph_run(string_id_type string_id, uint128_t render_trait) const; + bool store_glyph_run(string_id_type string_id, uint128_t render_trait, glyph_run *a_glyph_run); private: // std::map from render trait to glyph run typedef std::map trait_to_run_map; // std::map from character ID (including character index and render trait) to its glyph - std::map _glyph_store; + std::map _glyph_store; // std::map from string ID to glyph run // use hierarchical design so that when LRU string is evicted, all associated glyph runs are erased - std::map _glyph_run_store; + std::map _glyph_run_store; // least recently used glyph runs, indexed by string ID - lru_list _glyph_run_lru; + lru_list _glyph_run_lru; }; } diff --git a/gdipp_server/os2_metrics.cpp b/gdipp_server/os2_metrics.cpp index 0fd62e9..e094d64 100644 --- a/gdipp_server/os2_metrics.cpp +++ b/gdipp_server/os2_metrics.cpp @@ -50,20 +50,22 @@ bool os2_metrics::init(void *font_id) DWORD font_data_size; HDC font_holder = dc_pool_instance.claim(); + assert(font_holder != NULL); + font_mgr_instance.select_font(font_id, font_holder); - font_data_size = font_mgr_instance.lookup_font_data(font_id, OS2_TABLE_TAG, offsetof(TT_OS2, xAvgCharWidth), reinterpret_cast(&_xAvgCharWidth), sizeof(_xAvgCharWidth), font_holder); + font_data_size = GetFontData(font_holder, OS2_TABLE_TAG, offsetof(TT_OS2, xAvgCharWidth), reinterpret_cast(&_xAvgCharWidth), sizeof(_xAvgCharWidth)); if (font_data_size == GDI_ERROR) goto failed_init_os2_metrics; - font_data_size = font_mgr_instance.lookup_font_data(font_id, OS2_TABLE_TAG, offsetof(TT_OS2, usWeightClass), reinterpret_cast(&_usWeightClass), sizeof(_usWeightClass), font_holder); + font_data_size = GetFontData(font_holder, OS2_TABLE_TAG, offsetof(TT_OS2, usWeightClass), reinterpret_cast(&_usWeightClass), sizeof(_usWeightClass)); if (font_data_size == GDI_ERROR) goto failed_init_os2_metrics; - font_data_size = font_mgr_instance.lookup_font_data(font_id, OS2_TABLE_TAG, offsetof(TT_OS2, usWidthClass), reinterpret_cast(&_usWidthClass), sizeof(_usWidthClass), font_holder); + font_data_size = GetFontData(font_holder, OS2_TABLE_TAG, offsetof(TT_OS2, usWidthClass), reinterpret_cast(&_usWidthClass), sizeof(_usWidthClass)); if (font_data_size == GDI_ERROR) goto failed_init_os2_metrics; - font_data_size = font_mgr_instance.lookup_font_data(font_id, OS2_TABLE_TAG, offsetof(TT_OS2, fsSelection), reinterpret_cast(&_fsSelection), sizeof(_fsSelection), font_holder); + font_data_size = GetFontData(font_holder, OS2_TABLE_TAG, offsetof(TT_OS2, fsSelection), reinterpret_cast(&_fsSelection), sizeof(_fsSelection)); if (font_data_size == GDI_ERROR) goto failed_init_os2_metrics; diff --git a/gdipp_server/rpc_server.cpp b/gdipp_server/rpc_server.cpp index a79e2d3..284c267 100644 --- a/gdipp_server/rpc_server.cpp +++ b/gdipp_server/rpc_server.cpp @@ -1,7 +1,8 @@ #include "stdafx.h" #include "rpc_server.h" #include "gdipp_lib/helper.h" -#include "gdipp_lib/lock.h" +#include "gdipp_lib/scoped_rw_lock.h" +#include "gdipp_lib/scoped_rw_lock.h" #include "gdipp_rpc/gdipp_rpc.h" #include "gdipp_server/freetype.h" #include "gdipp_server/ft_renderer.h" @@ -117,7 +118,7 @@ DWORD WINAPI start_gdipp_rpc_server(LPVOID lpParameter) //bool b_ret; RPC_STATUS rpc_status; - lock::initialize_locks(); + scoped_rw_lock::initialize(); server_cache_size = min(config_instance.get_number(L"/gdipp/server/cache_size/text()", server_config::CACHE_SIZE), 24); glyph_cache_instance.initialize(); initialize_freetype(); @@ -158,7 +159,6 @@ bool stop_gdipp_rpc_server() //assert(b_ret); destroy_freetype(); - lock::destory_locks(); return true; } @@ -185,19 +185,18 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) if (logfont_size != sizeof(LOGFONTW)) return RPC_S_INVALID_ARG; - HDC session_hdc = gdipp::dc_pool_instance.claim(); - if (session_hdc == NULL) - return RPC_S_OUT_OF_MEMORY; + HDC session_font_holder = gdipp::dc_pool_instance.claim(); + assert(session_font_holder != NULL); // register font with given LOGFONT structure const LOGFONTW *logfont = reinterpret_cast(logfont_buf); BYTE *outline_metrics_buf; unsigned long outline_metrics_size; - void *session_font_id = gdipp::font_mgr_instance.register_font(logfont, &outline_metrics_buf, &outline_metrics_size, session_hdc); + + void *session_font_id = gdipp::font_mgr_instance.register_font(session_font_holder, logfont, &outline_metrics_buf, &outline_metrics_size); if (session_font_id == NULL) { - // revert allocations - gdipp::dc_pool_instance.free(session_hdc); + gdipp::dc_pool_instance.free(session_font_holder); return RPC_S_INVALID_ARG; } @@ -211,22 +210,22 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) metric_face_name(outline_metrics)); if (session_render_config->renderer == gdipp::server_config::RENDERER_CLEARTYPE) { - gdipp::dc_pool_instance.free(session_hdc); + gdipp::dc_pool_instance.free(session_font_holder); return RPC_S_OK; } FT_Render_Mode session_render_mode; if (!gdipp::get_render_mode(session_render_config->render_mode, bits_per_pixel, logfont->lfQuality, &session_render_mode)) { - gdipp::dc_pool_instance.free(session_hdc); + gdipp::dc_pool_instance.free(session_font_holder); return RPC_S_INVALID_ARG; } gdipp::rpc_session *new_session = reinterpret_cast(MIDL_user_allocate(sizeof(gdipp::rpc_session))); new_session->bits_per_pixel = bits_per_pixel; + new_session->font_holder = session_font_holder; new_session->font_id = session_font_id; - new_session->hdc = session_hdc; new_session->log_font = *reinterpret_cast(logfont_buf); new_session->outline_metrics_buf = outline_metrics_buf; new_session->outline_metrics_size = outline_metrics_size; @@ -263,7 +262,7 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) /* [out] */ unsigned long *font_size) { const gdipp::rpc_session *curr_session = reinterpret_cast(h_session); - *font_size = gdipp::font_mgr_instance.lookup_font_data(curr_session->font_id, table, offset, NULL, 0); + *font_size = GetFontData(curr_session->font_holder, table, offset, NULL, 0); return RPC_S_OK; } @@ -279,7 +278,8 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) const gdipp::rpc_session *curr_session = reinterpret_cast(h_session); // TODO: output pointer is not allocated with MIDL_user_allocate - gdipp::font_mgr_instance.lookup_font_data(curr_session->font_id, table, offset, data_buf, buf_size); + // TODO: return value not returned + GetFontData(curr_session->font_holder, table, offset, data_buf, buf_size); return RPC_S_OK; } @@ -318,7 +318,8 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) const gdipp::rpc_session *curr_session = reinterpret_cast(h_session); // TODO: output pointer is not allocated with MIDL_user_allocate - gdipp::font_mgr_instance.lookup_glyph_indices(curr_session->font_id, str, count, gi); + // TODO: return value not returned + GetGlyphIndices(curr_session->font_holder, str, count, gi, GGI_MARK_NONEXISTING_GLYPHS); return RPC_S_OK; } @@ -338,7 +339,7 @@ void __RPC_USER MIDL_user_free(void __RPC_FAR *ptr) bool b_ret; // generate unique identifier for the string - const uint128_t string_id = gdipp::glyph_cache::get_string_id(string, count, !!is_glyph_index); + const gdipp::glyph_cache::string_id_type string_id = gdipp::glyph_cache::get_string_id(string, count, !!is_glyph_index); // check if a glyph run cached for the same rendering environment and string const gdipp::glyph_run *glyph_run = gdipp::glyph_cache_instance.lookup_glyph_run(string_id, curr_session->render_trait); @@ -408,9 +409,9 @@ error_status_t gdipp_rpc_end_session( if (curr_session == NULL) return RPC_S_INVALID_ARG; - gdipp::dc_pool_instance.free(curr_session->hdc); delete[] curr_session->outline_metrics_buf; delete curr_session->renderer; + gdipp::dc_pool_instance.free(curr_session->font_holder); MIDL_user_free(*h_session); *h_session = NULL; diff --git a/gdipp_server/rpc_server.h b/gdipp_server/rpc_server.h index bdf0a4e..7c61925 100644 --- a/gdipp_server/rpc_server.h +++ b/gdipp_server/rpc_server.h @@ -11,8 +11,8 @@ class renderer; struct rpc_session { unsigned short bits_per_pixel; + HDC font_holder; void *font_id; - HDC hdc; /* LOGFONT is not directly mapped to a font instead, it is just a hint of how to create a font -- 2.11.4.GIT