2 #include "rpc_server.h"
3 #include "gdipp_lib/helper.h"
4 #include "gdipp_lib/lock.h"
5 #include "gdipp_rpc/gdipp_rpc.h"
6 #include "gdipp_server/freetype.h"
7 #include "gdipp_server/ft_renderer.h"
8 #include "gdipp_server/ggo_renderer.h"
9 #include "gdipp_server/global.h"
10 #include "gdipp_server/helper.h"
15 HANDLE process_heap
= GetProcessHeap();
18 // rpc index functions
20 bool rpc_index_initialize()
24 i_ret = sqlite3_initialize();
25 if (i_ret != SQLITE_OK)
28 // open SQLite database in memory
29 i_ret = sqlite3_open(":memory:", &index_db_instance);
30 if (i_ret != SQLITE_OK)
33 // create index tables
34 i_ret = sqlite3_exec(index_db_instance, "CREATE TABLE session_index ('session_address' INTEGER NOT NULL)", NULL, NULL, NULL);
35 if (i_ret != SQLITE_OK)
38 i_ret = sqlite3_exec(index_db_instance, "CREATE TABLE glyph_run_index ('glyph_run_address' INTEGER NOT NULL)", NULL, NULL, NULL);
39 if (i_ret != SQLITE_OK)
45 bool rpc_index_shutdown()
47 return (sqlite3_shutdown() == SQLITE_OK);
50 const rpc_session *rpc_index_lookup_session(GDIPP_RPC_SESSION_HANDLE h_session)
54 const int session_id = reinterpret_cast<int>(h_session);
55 const rpc_session *curr_session = NULL;
57 sqlite3_stmt *select_stmt;
59 i_ret = sqlite3_prepare_v2(index_db_instance, "SELECT session_address FROM session_index WHERE ROWID = ?", -1, &select_stmt, NULL);
60 assert(i_ret == SQLITE_OK);
62 i_ret = sqlite3_bind_int(select_stmt, 0, session_id);
63 assert(i_ret == SQLITE_OK);
65 i_ret = sqlite3_step(select_stmt);
66 if (i_ret == SQLITE_ROW)
69 curr_session = reinterpret_cast<const rpc_session *>(sqlite3_column_int64(select_stmt, 0));
71 curr_session = reinterpret_cast<const rpc_session *>(sqlite3_column_int(select_stmt, 0));
75 i_ret = sqlite3_finalize(select_stmt);
76 assert(i_ret == SQLITE_OK);
81 const glyph_run *rpc_index_lookup_glyph_run(GDIPP_RPC_GLYPH_RUN_HANDLE h_glyph_run)
85 const int glyph_run_id = reinterpret_cast<int>(h_glyph_run);
86 const glyph_run *curr_glyph_run = NULL;
88 sqlite3_stmt *select_stmt;
90 i_ret = sqlite3_prepare_v2(index_db_instance, "SELECT glyph_run_address FROM glyph_run_index WHERE ROWID = ?", -1, &select_stmt, NULL);
91 assert(i_ret == SQLITE_OK);
93 i_ret = sqlite3_bind_int(select_stmt, 0, glyph_run_id);
94 assert(i_ret == SQLITE_OK);
96 i_ret = sqlite3_step(select_stmt);
97 if (i_ret == SQLITE_ROW)
100 curr_glyph_run = reinterpret_cast<const glyph_run *>(sqlite3_column_int64(select_stmt, 0));
102 curr_glyph_run = reinterpret_cast<const glyph_run *>(sqlite3_column_int(select_stmt, 0));
106 i_ret = sqlite3_finalize(select_stmt);
107 assert(i_ret == SQLITE_OK);
109 return curr_glyph_run;
112 DWORD WINAPI
start_gdipp_rpc_server(LPVOID lpParameter
)
114 if (process_heap
== NULL
)
118 RPC_STATUS rpc_status
;
120 lock::initialize_locks();
121 server_cache_size
= min(config_instance
.get_number(L
"/gdipp/server/cache_size/text()", server_config::CACHE_SIZE
), 24);
122 glyph_cache_instance
.initialize();
123 initialize_freetype();
125 //b_ret = rpc_index_initialize();
129 rpc_status
= RpcServerUseProtseqEpW(reinterpret_cast<RPC_WSTR
>(L
"ncalrpc"), RPC_C_PROTSEQ_MAX_REQS_DEFAULT
, reinterpret_cast<RPC_WSTR
>(L
"gdipp"), NULL
);
130 if (rpc_status
!= RPC_S_OK
)
133 rpc_status
= RpcServerRegisterIf(gdipp_rpc_v1_0_s_ifspec
, NULL
, NULL
);
134 if (rpc_status
!= RPC_S_OK
)
137 rpc_status
= RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT
, TRUE
);
138 if (rpc_status
!= RPC_S_OK
)
141 rpc_status
= RpcMgmtWaitServerListen();
142 if (rpc_status
!= RPC_S_OK
)
148 bool stop_gdipp_rpc_server()
151 RPC_STATUS rpc_status
;
153 rpc_status
= RpcMgmtStopServerListening(NULL
);
154 if (rpc_status
!= RPC_S_OK
)
157 //b_ret = rpc_index_shutdown();
161 lock::destory_locks();
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 HDC session_hdc
= gdipp::dc_pool_instance
.claim();
189 if (session_hdc
== NULL
)
190 return RPC_S_OUT_OF_MEMORY
;
192 // register font with given LOGFONT structure
193 const LOGFONTW
*logfont
= reinterpret_cast<const LOGFONTW
*>(logfont_buf
);
194 BYTE
*outline_metrics_buf
;
195 unsigned long outline_metrics_size
;
196 void *session_font_id
= gdipp::font_mgr_instance
.register_font(logfont
, &outline_metrics_buf
, &outline_metrics_size
, session_hdc
);
197 if (session_font_id
== NULL
)
199 // revert allocations
200 gdipp::dc_pool_instance
.free(session_hdc
);
201 return RPC_S_INVALID_ARG
;
204 const OUTLINETEXTMETRICW
*outline_metrics
= reinterpret_cast<const OUTLINETEXTMETRICW
*>(outline_metrics_buf
);
205 // generate config trait and retrieve font-specific config
206 const LONG point_size
= (logfont
->lfHeight
> 0 ? logfont
->lfHeight
: -MulDiv(logfont
->lfHeight
, 72, outline_metrics
->otmTextMetrics
.tmDigitizedAspectY
));
207 const char weight_class
= gdipp::get_gdi_weight_class(static_cast<unsigned short>(outline_metrics
->otmTextMetrics
.tmWeight
));
208 const gdipp::render_config_static
*session_render_config
= gdipp::font_render_config_cache_instance
.get_font_render_config(!!weight_class
,
209 !!outline_metrics
->otmTextMetrics
.tmItalic
,
211 metric_face_name(outline_metrics
));
212 if (session_render_config
->renderer
== gdipp::server_config::RENDERER_CLEARTYPE
)
214 gdipp::dc_pool_instance
.free(session_hdc
);
218 FT_Render_Mode session_render_mode
;
219 if (!gdipp::get_render_mode(session_render_config
->render_mode
, bits_per_pixel
, logfont
->lfQuality
, &session_render_mode
))
221 gdipp::dc_pool_instance
.free(session_hdc
);
222 return RPC_S_INVALID_ARG
;
225 gdipp::rpc_session
*new_session
= reinterpret_cast<gdipp::rpc_session
*>(MIDL_user_allocate(sizeof(gdipp::rpc_session
)));
227 new_session
->bits_per_pixel
= bits_per_pixel
;
228 new_session
->font_id
= session_font_id
;
229 new_session
->hdc
= session_hdc
;
230 new_session
->log_font
= *reinterpret_cast<const LOGFONTW
*>(logfont_buf
);
231 new_session
->outline_metrics_buf
= outline_metrics_buf
;
232 new_session
->outline_metrics_size
= outline_metrics_size
;
233 new_session
->render_config
= session_render_config
;
234 new_session
->render_mode
= session_render_mode
;
235 new_session
->render_trait
= gdipp::generate_render_trait(logfont
, new_session
->render_mode
);
237 // create session renderer
238 switch (session_render_config
->renderer
)
240 case gdipp::server_config::RENDERER_DIRECTWRITE
:
242 case gdipp::server_config::RENDERER_FREETYPE
:
243 new_session
->renderer
= new gdipp::ft_renderer(new_session
);
245 case gdipp::server_config::RENDERER_GETGLYPHOUTLINE
:
246 new_session
->renderer
= new gdipp::ggo_renderer(new_session
);
248 case gdipp::server_config::RENDERER_WIC
:
254 *h_session
= reinterpret_cast<GDIPP_RPC_SESSION_HANDLE
>(new_session
);
258 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_size(
259 /* [in] */ handle_t h_gdipp_rpc
,
260 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
261 /* [in] */ unsigned long table
,
262 /* [in] */ unsigned long offset
,
263 /* [out] */ unsigned long *font_size
)
265 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
266 *font_size
= gdipp::font_mgr_instance
.lookup_font_data(curr_session
->font_id
, table
, offset
, NULL
, 0);
271 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_get_font_data(
272 /* [in] */ handle_t h_gdipp_rpc
,
273 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
274 /* [in] */ unsigned long table
,
275 /* [in] */ unsigned long offset
,
276 /* [size_is][out] */ byte
*data_buf
,
277 /* [in] */ unsigned long buf_size
)
279 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
281 // TODO: output pointer is not allocated with MIDL_user_allocate
282 gdipp::font_mgr_instance
.lookup_font_data(curr_session
->font_id
, 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 gdipp::font_mgr_instance
.lookup_glyph_indices(curr_session
->font_id
, str
, count
, gi
);
326 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_make_bitmap_glyph_run(
327 /* [in] */ handle_t h_gdipp_rpc
,
328 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
329 /* [string][in] */ const wchar_t *string
,
330 /* [in] */ unsigned int count
,
331 /* [in] */ boolean is_glyph_index
,
332 /* [out] */ gdipp_rpc_bitmap_glyph_run
*glyph_run_ptr
)
335 return RPC_S_INVALID_ARG
;
337 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(h_session
);
340 // generate unique identifier for the string
341 const uint128_t string_id
= gdipp::glyph_cache::get_string_id(string
, count
, !!is_glyph_index
);
343 // check if a glyph run cached for the same rendering environment and string
344 const gdipp::glyph_run
*glyph_run
= gdipp::glyph_cache_instance
.lookup_glyph_run(string_id
, curr_session
->render_trait
);
347 // no cached glyph run. render new glyph run
348 gdipp::glyph_run
*new_glyph_run
= new gdipp::glyph_run();
349 b_ret
= curr_session
->renderer
->render(!!is_glyph_index
, string
, count
, new_glyph_run
);
351 return RPC_S_OUT_OF_MEMORY
;
354 gdipp::glyph_cache_instance
.store_glyph_run(string_id
, curr_session
->render_trait
, new_glyph_run
);
355 glyph_run
= new_glyph_run
;
358 // convert internal glyph run to RPC exchangable format
360 // allocate space for glyph run
361 glyph_run_ptr
->count
= static_cast<UINT
>(glyph_run
->glyphs
.size());
362 glyph_run_ptr
->glyphs
= reinterpret_cast<gdipp_rpc_bitmap_glyph
*>(MIDL_user_allocate(sizeof(gdipp_rpc_bitmap_glyph
) * glyph_run_ptr
->count
));
363 glyph_run_ptr
->ctrl_boxes
= reinterpret_cast<RECT
*>(MIDL_user_allocate(sizeof(RECT
) * glyph_run_ptr
->count
));
364 glyph_run_ptr
->black_boxes
= reinterpret_cast<RECT
*>(MIDL_user_allocate(sizeof(RECT
) * glyph_run_ptr
->count
));
365 glyph_run_ptr
->render_mode
= curr_session
->render_mode
;
367 for (unsigned int i
= 0; i
< glyph_run_ptr
->count
; ++i
)
369 glyph_run_ptr
->ctrl_boxes
[i
] = glyph_run
->ctrl_boxes
[i
];
370 glyph_run_ptr
->black_boxes
[i
] = glyph_run
->black_boxes
[i
];
372 if (glyph_run
->glyphs
[i
] == NULL
)
374 glyph_run_ptr
->glyphs
[i
].buffer
= NULL
;
378 const FT_BitmapGlyph bmp_glyph
= reinterpret_cast<const FT_BitmapGlyph
>(glyph_run
->glyphs
[i
]);
379 glyph_run_ptr
->glyphs
[i
].left
= bmp_glyph
->left
;
380 glyph_run_ptr
->glyphs
[i
].top
= bmp_glyph
->top
;
381 glyph_run_ptr
->glyphs
[i
].rows
= bmp_glyph
->bitmap
.rows
;
382 glyph_run_ptr
->glyphs
[i
].width
= bmp_glyph
->bitmap
.width
;
383 glyph_run_ptr
->glyphs
[i
].pitch
= bmp_glyph
->bitmap
.pitch
;
384 const int buffer_size
= bmp_glyph
->bitmap
.rows
* abs(bmp_glyph
->bitmap
.pitch
);
385 glyph_run_ptr
->glyphs
[i
].buffer
= reinterpret_cast<byte
*>(MIDL_user_allocate(buffer_size
));
386 memcpy(glyph_run_ptr
->glyphs
[i
].buffer
, bmp_glyph
->bitmap
.buffer
, buffer_size
);
392 /* [fault_status][comm_status] */ error_status_t
gdipp_rpc_make_outline_glyph_run(
393 /* [in] */ handle_t h_gdipp_rpc
,
394 /* [context_handle_noserialize][in] */ GDIPP_RPC_SESSION_HANDLE h_session
,
395 /* [string][in] */ const wchar_t *string
,
396 /* [in] */ unsigned int count
,
397 /* [in] */ boolean is_glyph_index
,
398 /* [out] */ gdipp_rpc_outline_glyph_run
*glyph_run_ptr
)
400 return ERROR_CALL_NOT_IMPLEMENTED
;
403 error_status_t
gdipp_rpc_end_session(
404 /* [in] */ handle_t h_gdipp_rpc
,
405 /* [out][in] */ GDIPP_RPC_SESSION_HANDLE
*h_session
)
407 const gdipp::rpc_session
*curr_session
= reinterpret_cast<const gdipp::rpc_session
*>(*h_session
);
408 if (curr_session
== NULL
)
409 return RPC_S_INVALID_ARG
;
411 gdipp::dc_pool_instance
.free(curr_session
->hdc
);
412 delete[] curr_session
->outline_metrics_buf
;
413 delete curr_session
->renderer
;
414 MIDL_user_free(*h_session
);
420 void __RPC_USER
GDIPP_RPC_SESSION_HANDLE_rundown(GDIPP_RPC_SESSION_HANDLE h_session
)
422 error_status_t e
= gdipp_rpc_end_session(NULL
, &h_session
);