2 #include "rpc_server.h"
3 #include "gdipp_lib/helper.h"
4 #include "gdipp_lib/scoped_rw_lock.h"
5 #include "gdipp_lib/scoped_rw_lock.h"
6 #include "gdipp_rpc/gdipp_rpc.h"
7 #include "gdipp_server/freetype.h"
8 #include "gdipp_server/ft_renderer.h"
9 #include "gdipp_server/ggo_renderer.h"
10 #include "gdipp_server/global.h"
11 #include "gdipp_server/helper.h"
16 HANDLE process_heap
= GetProcessHeap();
19 // rpc index functions
21 bool rpc_index_initialize()
25 i_ret = sqlite3_initialize();
26 if (i_ret != SQLITE_OK)
29 // open SQLite database in memory
30 i_ret = sqlite3_open(":memory:", &index_db_instance);
31 if (i_ret != SQLITE_OK)
34 // create index tables
35 i_ret = sqlite3_exec(index_db_instance, "CREATE TABLE session_index ('session_address' INTEGER NOT NULL)", NULL, NULL, NULL);
36 if (i_ret != SQLITE_OK)
39 i_ret = sqlite3_exec(index_db_instance, "CREATE TABLE glyph_run_index ('glyph_run_address' INTEGER NOT NULL)", NULL, NULL, NULL);
40 if (i_ret != SQLITE_OK)
46 bool rpc_index_shutdown()
48 return (sqlite3_shutdown() == SQLITE_OK);
51 const rpc_session *rpc_index_lookup_session(GDIPP_RPC_SESSION_HANDLE h_session)
55 const int session_id = reinterpret_cast<int>(h_session);
56 const rpc_session *curr_session = NULL;
58 sqlite3_stmt *select_stmt;
60 i_ret = sqlite3_prepare_v2(index_db_instance, "SELECT session_address FROM session_index WHERE ROWID = ?", -1, &select_stmt, NULL);
61 assert(i_ret == SQLITE_OK);
63 i_ret = sqlite3_bind_int(select_stmt, 0, session_id);
64 assert(i_ret == SQLITE_OK);
66 i_ret = sqlite3_step(select_stmt);
67 if (i_ret == SQLITE_ROW)
70 curr_session = reinterpret_cast<const rpc_session *>(sqlite3_column_int64(select_stmt, 0));
72 curr_session = reinterpret_cast<const rpc_session *>(sqlite3_column_int(select_stmt, 0));
76 i_ret = sqlite3_finalize(select_stmt);
77 assert(i_ret == SQLITE_OK);
82 const glyph_run *rpc_index_lookup_glyph_run(GDIPP_RPC_GLYPH_RUN_HANDLE h_glyph_run)
86 const int glyph_run_id = reinterpret_cast<int>(h_glyph_run);
87 const glyph_run *curr_glyph_run = NULL;
89 sqlite3_stmt *select_stmt;
91 i_ret = sqlite3_prepare_v2(index_db_instance, "SELECT glyph_run_address FROM glyph_run_index WHERE ROWID = ?", -1, &select_stmt, NULL);
92 assert(i_ret == SQLITE_OK);
94 i_ret = sqlite3_bind_int(select_stmt, 0, glyph_run_id);
95 assert(i_ret == SQLITE_OK);
97 i_ret = sqlite3_step(select_stmt);
98 if (i_ret == SQLITE_ROW)
101 curr_glyph_run = reinterpret_cast<const glyph_run *>(sqlite3_column_int64(select_stmt, 0));
103 curr_glyph_run = reinterpret_cast<const glyph_run *>(sqlite3_column_int(select_stmt, 0));
107 i_ret = sqlite3_finalize(select_stmt);
108 assert(i_ret == SQLITE_OK);
110 return curr_glyph_run;
113 DWORD WINAPI
start_gdipp_rpc_server(LPVOID lpParameter
)
115 if (process_heap
== NULL
)
119 RPC_STATUS rpc_status
;
121 scoped_rw_lock::initialize();
122 server_cache_size
= min(config_instance
.get_number(L
"/gdipp/server/cache_size/text()", server_config::CACHE_SIZE
), 24);
123 glyph_cache_instance
.initialize();
124 initialize_freetype();
126 //b_ret = rpc_index_initialize();
130 rpc_status
= RpcServerUseProtseqEpW(reinterpret_cast<RPC_WSTR
>(L
"ncalrpc"), RPC_C_PROTSEQ_MAX_REQS_DEFAULT
, reinterpret_cast<RPC_WSTR
>(L
"gdipp"), NULL
);
131 if (rpc_status
!= RPC_S_OK
)
134 rpc_status
= RpcServerRegisterIf(gdipp_rpc_v1_0_s_ifspec
, NULL
, NULL
);
135 if (rpc_status
!= RPC_S_OK
)
138 rpc_status
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
);
139 if (rpc_status
!= RPC_S_OK
)
142 rpc_status
= RpcMgmtWaitServerListen();
143 if (rpc_status
!= RPC_S_OK
)
149 bool stop_gdipp_rpc_server()
152 RPC_STATUS rpc_status
;
154 rpc_status
= RpcMgmtStopServerListening(NULL
);
155 if (rpc_status
!= RPC_S_OK
)
158 //b_ret = rpc_index_shutdown();
168 void __RPC_FAR
*__RPC_USER
MIDL_user_allocate(size_t size
)
170 return HeapAlloc(gdipp::process_heap
, HEAP_GENERATE_EXCEPTIONS
, size
);
173 void __RPC_USER
MIDL_user_free(void __RPC_FAR
*ptr
)
175 HeapFree(gdipp::process_heap
, 0, ptr
);
178 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_begin_session(
179 /* [in] */ handle_t h_gdipp_rpc
,
180 /* [size_is][in] */ const byte
*logfont_buf
,
181 /* [in] */ unsigned long logfont_size
,
182 /* [in] */ unsigned short bits_per_pixel
,
183 /* [out] */ GDIPP_RPC_SESSION_HANDLE
*h_session
)
185 if (logfont_size
!= sizeof(LOGFONTW
))
186 return RPC_S_INVALID_ARG
;
188 const HDC session_font_holder
= gdipp::dc_pool_instance
.claim();
189 assert(session_font_holder
!= NULL
);
191 // register font with given LOGFONT structure
192 const LOGFONTW
*logfont
= reinterpret_cast<const LOGFONTW
*>(logfont_buf
);
193 BYTE
*outline_metrics_buf
;
194 unsigned long outline_metrics_size
;
196 void *session_font_id
= gdipp::font_mgr_instance
.register_font(session_font_holder
, logfont
, &outline_metrics_buf
, &outline_metrics_size
);
197 if (session_font_id
== NULL
)
199 gdipp::dc_pool_instance
.free(session_font_holder
);
200 return RPC_S_INVALID_ARG
;
203 const OUTLINETEXTMETRICW
*outline_metrics
= reinterpret_cast<const OUTLINETEXTMETRICW
*>(outline_metrics_buf
);
204 // generate config trait and retrieve font-specific config
205 const LONG point_size
= (logfont
->lfHeight
> 0 ? logfont
->lfHeight
: -MulDiv(logfont
->lfHeight
, 72, outline_metrics
->otmTextMetrics
.tmDigitizedAspectY
));
206 const char weight_class
= gdipp::get_gdi_weight_class(static_cast<unsigned short>(outline_metrics
->otmTextMetrics
.tmWeight
));
207 const gdipp::render_config_static
*session_render_config
= gdipp::font_render_config_cache_instance
.get_font_render_config(!!weight_class
,
208 !!outline_metrics
->otmTextMetrics
.tmItalic
,
210 metric_face_name(outline_metrics
));
211 if (session_render_config
->renderer
== gdipp::server_config::RENDERER_CLEARTYPE
)
213 gdipp::dc_pool_instance
.free(session_font_holder
);
217 FT_Render_Mode session_render_mode
;
218 if (!gdipp::get_render_mode(session_render_config
->render_mode
, bits_per_pixel
, logfont
->lfQuality
, &session_render_mode
))
220 gdipp::dc_pool_instance
.free(session_font_holder
);
221 return RPC_S_INVALID_ARG
;
224 gdipp::rpc_session
*new_session
= reinterpret_cast<gdipp::rpc_session
*>(MIDL_user_allocate(sizeof(gdipp::rpc_session
)));
226 new_session
->bits_per_pixel
= bits_per_pixel
;
227 new_session
->font_holder
= session_font_holder
;
228 new_session
->font_id
= session_font_id
;
229 new_session
->log_font
= *reinterpret_cast<const LOGFONTW
*>(logfont_buf
);
230 new_session
->outline_metrics_buf
= outline_metrics_buf
;
231 new_session
->outline_metrics_size
= outline_metrics_size
;
232 new_session
->render_config
= session_render_config
;
233 new_session
->render_mode
= session_render_mode
;
234 new_session
->render_trait
= gdipp::generate_render_trait(logfont
, new_session
->render_mode
);
236 // create session renderer
237 switch (session_render_config
->renderer
)
239 case gdipp::server_config::RENDERER_DIRECTWRITE
:
241 case gdipp::server_config::RENDERER_FREETYPE
:
242 new_session
->renderer
= new gdipp::ft_renderer(new_session
);
244 case gdipp::server_config::RENDERER_GETGLYPHOUTLINE
:
245 new_session
->renderer
= new gdipp::ggo_renderer(new_session
);
247 case gdipp::server_config::RENDERER_WIC
:
253 *h_session
= reinterpret_cast<GDIPP_RPC_SESSION_HANDLE
>(new_session
);
257 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_size(
258 /* [in] */ handle_t h_gdipp_rpc
,
259 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
260 /* [in] */ unsigned long table
,
261 /* [in] */ unsigned long offset
,
262 /* [out] */ unsigned long *font_size
)
264 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
265 *font_size
= GetFontData(curr_session
->font_holder
, table
, offset
, NULL
, 0);
270 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_data(
271 /* [in] */ handle_t h_gdipp_rpc
,
272 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
273 /* [in] */ unsigned long table
,
274 /* [in] */ unsigned long offset
,
275 /* [size_is][out] */ byte
*data_buf
,
276 /* [in] */ unsigned long buf_size
)
278 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
280 // TODO: output pointer is not allocated with MIDL_user_allocate
281 // TODO: return value not returned
282 GetFontData(curr_session
->font_holder
, table
, offset
, data_buf
, buf_size
);
287 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_metrics_size(
288 /* [in] */ handle_t h_gdipp_rpc
,
289 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
290 /* [out] */ unsigned long *metrics_size
)
292 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
293 *metrics_size
= curr_session
->outline_metrics_size
;
298 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_metrics_data(
299 /* [in] */ handle_t h_gdipp_rpc
,
300 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
301 /* [size_is][out] */ byte
*metrics_buf
,
302 /* [in] */ unsigned long buf_size
)
304 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
305 const DWORD copy_size
= min(curr_session
->outline_metrics_size
, buf_size
);
306 CopyMemory(metrics_buf
, curr_session
->outline_metrics_buf
, copy_size
);
311 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_glyph_indices(
312 /* [in] */ handle_t h_gdipp_rpc
,
313 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
314 /* [size_is][string][in] */ const wchar_t *str
,
315 /* [in] */ int count
,
316 /* [size_is][out] */ unsigned short *gi
)
318 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
320 // TODO: output pointer is not allocated with MIDL_user_allocate
321 // TODO: return value not returned
322 GetGlyphIndices(curr_session
->font_holder
, str
, count
, gi
, GGI_MARK_NONEXISTING_GLYPHS
);
327 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_make_bitmap_glyph_run(
328 /* [in] */ handle_t h_gdipp_rpc
,
329 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
330 /* [string][in] */ const wchar_t *string
,
331 /* [in] */ unsigned int count
,
332 /* [in] */ boolean is_glyph_index
,
333 /* [out] */ gdipp_rpc_bitmap_glyph_run
*glyph_run_ptr
)
336 return RPC_S_INVALID_ARG
;
338 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
341 // generate unique identifier for the string
342 const gdipp::glyph_cache::string_id_type string_id
= gdipp::glyph_cache::get_string_id(string
, count
, !!is_glyph_index
);
344 // check if a glyph run cached for the same rendering environment and string
345 const gdipp::glyph_run
*glyph_run
= gdipp::glyph_cache_instance
.lookup_glyph_run(string_id
, curr_session
->render_trait
);
348 // no cached glyph run. render new glyph run
349 gdipp::glyph_run
*new_glyph_run
= new gdipp::glyph_run();
350 b_ret
= curr_session
->renderer
->render(!!is_glyph_index
, string
, count
, new_glyph_run
);
352 return RPC_S_OUT_OF_MEMORY
;
355 gdipp::glyph_cache_instance
.store_glyph_run(string_id
, curr_session
->render_trait
, new_glyph_run
);
356 glyph_run
= new_glyph_run
;
359 // convert internal glyph run to RPC exchangable format
361 // allocate space for glyph run
362 glyph_run_ptr
->count
= static_cast<UINT
>(glyph_run
->glyphs
.size());
363 glyph_run_ptr
->glyphs
= reinterpret_cast<gdipp_rpc_bitmap_glyph
*>(MIDL_user_allocate(sizeof(gdipp_rpc_bitmap_glyph
) * glyph_run_ptr
->count
));
364 glyph_run_ptr
->ctrl_boxes
= reinterpret_cast<RECT
*>(MIDL_user_allocate(sizeof(RECT
) * glyph_run_ptr
->count
));
365 glyph_run_ptr
->black_boxes
= reinterpret_cast<RECT
*>(MIDL_user_allocate(sizeof(RECT
) * glyph_run_ptr
->count
));
366 glyph_run_ptr
->render_mode
= curr_session
->render_mode
;
368 for (unsigned int i
= 0; i
< glyph_run_ptr
->count
; ++i
)
370 glyph_run_ptr
->ctrl_boxes
[i
] = glyph_run
->ctrl_boxes
[i
];
371 glyph_run_ptr
->black_boxes
[i
] = glyph_run
->black_boxes
[i
];
373 if (glyph_run
->glyphs
[i
] == NULL
)
375 glyph_run_ptr
->glyphs
[i
].buffer
= NULL
;
379 const FT_BitmapGlyph bmp_glyph
= reinterpret_cast<const FT_BitmapGlyph
>(glyph_run
->glyphs
[i
]);
380 glyph_run_ptr
->glyphs
[i
].left
= bmp_glyph
->left
;
381 glyph_run_ptr
->glyphs
[i
].top
= bmp_glyph
->top
;
382 glyph_run_ptr
->glyphs
[i
].rows
= bmp_glyph
->bitmap
.rows
;
383 glyph_run_ptr
->glyphs
[i
].width
= bmp_glyph
->bitmap
.width
;
384 glyph_run_ptr
->glyphs
[i
].pitch
= bmp_glyph
->bitmap
.pitch
;
385 const int buffer_size
= bmp_glyph
->bitmap
.rows
* abs(bmp_glyph
->bitmap
.pitch
);
386 glyph_run_ptr
->glyphs
[i
].buffer
= reinterpret_cast<byte
*>(MIDL_user_allocate(buffer_size
));
387 memcpy(glyph_run_ptr
->glyphs
[i
].buffer
, bmp_glyph
->bitmap
.buffer
, buffer_size
);
393 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_make_outline_glyph_run(
394 /* [in] */ handle_t h_gdipp_rpc
,
395 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
396 /* [string][in] */ const wchar_t *string
,
397 /* [in] */ unsigned int count
,
398 /* [in] */ boolean is_glyph_index
,
399 /* [out] */ gdipp_rpc_outline_glyph_run
*glyph_run_ptr
)
401 return ERROR_CALL_NOT_IMPLEMENTED
;
404 error_status_t
gdipp_rpc_end_session(
405 /* [in] */ handle_t h_gdipp_rpc
,
406 /* [out][in] */ GDIPP_RPC_SESSION_HANDLE
*h_session
)
408 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(*h_session
);
409 if (curr_session
== NULL
)
410 return RPC_S_INVALID_ARG
;
412 delete[] curr_session
->outline_metrics_buf
;
413 delete curr_session
->renderer
;
414 gdipp::dc_pool_instance
.free(curr_session
->font_holder
);
415 MIDL_user_free(*h_session
);
421 void __RPC_USER
GDIPP_RPC_SESSION_HANDLE_rundown(GDIPP_RPC_SESSION_HANDLE h_session
)
423 error_status_t e
= gdipp_rpc_end_session(NULL
, &h_session
);